#!/bin/sh # # name : /secure/rotate_log # # History : # Original release 0.8 from Steven C. Simmons # Changes by Sean Boran: # <1> V1.1 May.11'93 (Sean Boran) # <2> V1.2 Nov.29'93 # Use gzip instead of compress # <2bis> see <2> 13.12.93 defined path to gzip # <3> Oct.20'96 : Removed warning "Missing backup log....Continuing" # <4> Nov.15'99 : Set defaults, remove logcheck offsets. # <5> Dec.16'99 : Send Kill -1 AFTER creating new empty log # <6> Feb.26'01 : chown path, use .gz not .Z # <7> Aug.11'01 : define PATH for gzip # <8> Jan.21'02 : Restart syslog with pid file in many locations # By jesus.martin-bernardo@vodafone.com: # <9> Feb.05'03 : Define a path to gzip with '-c' on command line # rather than use value of COMPRESS # # Function: see also man page. # # Shell script to rotate a log. Usage: # # rotate_log log [ -L src_dir ] [ -n n ] [ -c [gzip dir]] [-s] [ -B backup_dir ] # [ -b backup_name ] [ -m mode ] [ -o owner ] [ -g group ] # [ -M mode ] [ -O owner ] [ -G group ] [ -e prolog_cmd ] # [ -E postlog_cmd ] logfile # # where the switches mean: # # -L Name of the directory 'log' is found in. # -n Number of backup copies to keep. # -s Skip empty logs. # -c Compress the backup copy. You can add a path to the gzip file<9> # -B Dir to keep the backup copies in. # -b Name of backup copy. # -m Mode of new log. # -o Owner of new log (only root can use this option). # -g Group of new log (only root can use this option). # -M Mode of backup copy. # -O Owner of backup copy (only root can use this option). # -G Group of backup copy (only root can use this option). # -e Command to be executed immediately before copying the logfile. # -E Command to be executed immediately after copying the logfile. # # Stylistic note -- any error that says 'Unexpected error' means I # thought this particular error can't happen. # # This program is Copyright 1989, Steven C. Simmons. It may be freely # redistributed provided this notice remains intact and any changes you # make are clearly marked as such. # # $Source: /home/lokkur/scs/src/rotate_log/rotate_log/RCS/rotate_log,v $ # # Revision 0.9 Feb.05'03 14:30:00 <9> # Added to -c: You can define a path to gzip # Fixed bug: Define COMPRESS="", until now the script compress allways # # $Revision: 0.8 $ # # $Author: scs $ $Date: 91/08/02 19:01:20 $ # # $State: Exp $ $Locker: $ # # $Log: rotate_log,v $ # Revision 0.8 91/08/02 19:01:20 scs # Corrected error in paraterization of chmod/chgrp/chown. Didn't # this get fixed once before? # # Revision 0.7 91/04/30 22:10:10 scs # Added -s switch. # # Revision 0.6 91/04/27 16:16:59 scs # Fixed bug with -b/-n combo losing arguements. Patch supplied by # Michael Bredeweg (...clif!comnet!mike). # # Revision 0.5 91/04/03 19:49:00 scs # Parameterized locations of chmod, chgrp, chown. # ###################################################################3 SCRIPT=`basename $0` # # PATH: to allow this script to run on several machines, I define a # a PATH to be able to find gzip. <7> PATH="/usr/bin:/bin:/usr/local/bin"; export PATH # # Commonly used commands # #COMPRESS="" #COMPRESS="/usr/local/bin/gzip "; COMPRESS="gzip "; MV=/bin/mv CP=/bin/cp CHMOD=/bin/chmod CHOWN=/bin/chown CHGRP=/bin/chgrp # # Assign default values as needed <4> # #SOURCE_DIR="" SOURCE_DIR="/var/log/" SOURCE_NAME="" BACKUP_NAME="" BACKUP_DIR="" BACKUP_COUNT="3" SOURCE_MODE="640" SOURCE_OWNER="" SOURCE_GROUP="" BACKUP_MODE="440" BACKUP_OWNER="" BACKUP_GROUP="" #SKIP_FLAG="false" SKIP_FLAG="true" # Restart syslog properly, or as best we can <8> if [ -f /etc/syslog.pid ] ; then CMD_AFTER="kill -1 `cat /etc/syslog.pid`" elif [ -f /var/run/syslog.pid ] ; then CMD_AFTER="kill -1 `cat /var/run/syslog.pid`" else CMD_AFTER="`pkill -1 syslogd`" fi # # Basic switch parsing. Right now, this forces us to use whitespace # between switch char and actual execution. Whenever we get data # for a switch, errorcheck it immediately. # while [ "$#" -gt "0" ] ; do case $1 in -L ) if [ "$2" = "" ] ; then echo "${SCRIPT}: The $1 switch requires a directory name. Aborting." exit 0 fi if [ -w "${2}" -a -d "${2}" ] ; then : else echo "${SCRIPT}: Sorry, you cannot modify the directory ${2}. Aborting." exit 0 fi SOURCE_DIR="${2}/" shift ;; -b ) if [ "$2" = "" ] ; then echo "${SCRIPT}: The $1 switch requires a backup name. Aborting." exit 0 fi BACKUP_NAME="$2" shift ;; -B ) if [ "$2" = "" ] ; then echo "${SCRIPT}: The $1 switch requires a directory name. Aborting." exit 0 fi if [ -w "${2}" -a -d "${2}" ] ; then : else echo "${SCRIPT}: Sorry, you cannot create files in ${DIR}. Aborting." exit 0 fi BACKUP_DIR="${2}/" shift ;; -n ) if [ "$2" = "" ] ; then echo "${SCRIPT}: The $1 switch requires a backup count. Aborting." exit 0 fi if echo $2 | grep '[^0-9]' > /dev/null 2>&1 ; then echo "${SCRIPT}: The backup count ($2) must be a positive number. Aborting." exit 0 fi if [ $2 -eq 0 ] ; then echo "${SCRIPT}: The backup count ($2) must be greater than zero. Aborting." exit 0 fi BACKUP_COUNT="$2" shift ;; -s ) SKIP_FLAG="true" ;; # -c ) COMPRESS="compress -f" # -c ) COMPRESS="gzip -S .gz " # use gzip but with .Z <2> -c ) if [ "$2" = "" ] ; then # <9> COMPRESS="gzip -S .gz " else if [ -d "$2" -a -x "$2/gzip" -a -r "$2/gzip"] ; then COMPRESS= "$2/gzip -S .gz" else echo "Path to gzip is not correct" fi fi shift ;; -m ) if [ "$2" = "" ] ; then echo "${SCRIPT}: The $1 switch requires a permissions mode. Aborting." exit 0 fi SOURCE_MODE="$2" shift ;; -M ) if [ "$2" = "" ] ; then echo "${SCRIPT}: The $1 switch requires a permissions mode. Aborting." exit 0 fi BACKUP_MODE="$2" shift ;; -o ) if [ "$2" = "" ] ; then echo "${SCRIPT}: The $1 switch requires the name of the new owner. Aborting." exit 0 fi if grep '^${2}:' < /etc/passwd > /dev/null 2>&1 ; then echo "${SCRIPT}: No such login id as $2. Aborting." exit 0 fi SOURCE_OWNER="$2" shift ;; -O ) if [ "$2" = "" ] ; then echo "${SCRIPT}: The $1 switch requires the name of the new owner. Aborting." exit 0 fi if grep '^${2}:' < /etc/passwd > /dev/null 2>&1 ; then echo "${SCRIPT}: No such login id as $2. Aborting." exit 0 fi BACKUP_OWNER="$2" shift ;; -g ) if [ "$2" = "" ] ; then echo "${SCRIPT}: The $1 switch requires the name of the new group. Aborting." exit 0 fi if grep '^${2}:' < /etc/group > /dev/null 2>&1 ; then echo "${SCRIPT}: No such group as $2. Aborting." exit 0 fi SOURCE_GROUP="$2" shift ;; -G ) if [ "$2" = "" ] ; then echo "${SCRIPT}: The $1 switch requires the name of the new group. Aborting." exit 0 fi if grep '^${2}:' < /etc/group > /dev/null 2>&1 ; then echo "${SCRIPT}: No such group as $2. Aborting." exit 0 fi BACKUP_GROUP="$2" shift ;; -e ) if [ "$2" = "" ] ; then echo "${SCRIPT}: The $1 switch requires a command to be executed. Aborting." exit 0 fi CMD_BEFORE="${2}" shift ;; -E ) if [ "$2" = "" ] ; then echo "${SCRIPT}: The $1 switch requires a command to be executed. Aborting." exit 0 fi CMD_AFTER="${2}" shift ;; -* ) echo "${SCRIPT}: No such switch as $1. Aborting." exit 0 ;; * ) if [ "${SOURCE_NAME}" != "" ] ; then echo "${SCRIPT}: You must specify only one log file. Aborting." exit 0 else SOURCE_NAME=$1 fi ;; esac shift done if [ "${SOURCE_NAME}" = "" ] ; then echo "${SCRIPT}: You must specify a log file. Aborting." exit 0 fi # # Do sanity checks # # If he specified a source directory or backup directory, the source # and backup file names cannot contain a slash. # if [ "${SOURCE_DIR}" != "" ] ; then if echo $SOURCE_NAME | grep / > /dev/null ; then cat << EOF ${SCRIPT}: If you specify a source directory (eg, -L ${SOURCE_DIR}), then the log file name (${SOURCE_NAME}) must be a simple file name, ie, not containing any slashes. Aborting. EOF exit 0 fi # # If they don't explicitly select a backup directory but the # do specify a log directory, use the same for both. # if [ "${BACKUP_DIR}" = "" ] ; then BACKUP_DIR="${SOURCE_DIR}" fi fi if [ "${BACKUP_DIR}" != "" ] ; then if echo $BACKUP_NAME | grep / > /dev/null ; then cat << EOF ${SCRIPT}: If you specify a backup directory (eg, -B ${BACKUP_DIR}), then the backup log name (${BACKUP_NAME}) must be a simple file name, ie, not containing any slashes. Aborting. EOF exit 0 fi fi # # Make sure we can mod the directory where the log is. # if [ -w `dirname "${SOURCE_NAME}"` ] ; then : else cat << EOF ${SCRIPT}: Sorry, you do not have permission to move/rename the log file (file '`basename ${SOURCE_NAME}`', directory '`dirname ${SOURCE_NAME}`'). Aborting. EOF exit 0 fi # # Make sure we can read/write the log itself. # SOURCE_PATH="${SOURCE_DIR}${SOURCE_NAME}" if [ -w "${SOURCE_PATH}" -a -r "${SOURCE_PATH}" ] ; then : else echo "${SCRIPT}: Sorry, you do not have permission to read and modify" echo "the file '${SOURCE_PATH}'. Aborting." exit 0 fi # # If the log is empty and the skip flag (-s) is set, do nothing. # if [ "${SKIP_FLAG}" = "true" ] ; then set `wc -c ${SOURCE_PATH}` if [ 0 = $1 ] ; then exit 0 fi fi # # Make sure root operations are only run by root # if [ "${BACKUP_OWNER}" != "" -o "${SOURCE_OWNER}" != "" -o "${BACKUP_GROUP}" != "" -o "${SOURCE_GROUP}" != "" ] then set `who am i` if [ "root" != "$1" ] ; then echo "${SCRIPT}: Sorry, you can only change owner or group if you are root." echo "Aborting." exit 0 fi fi # # Build the list of backup names, in reverse order. Make them # full pathnames. # if [ "${BACKUP_NAME}" = "" ] ; then BACKUP_NAME="${SOURCE_NAME}" fi while expr $BACKUP_COUNT \> 0 > /dev/null ; do BACKUP_COUNT=`expr $BACKUP_COUNT - 1` BACKUP_FILES="${BACKUP_FILES} ${BACKUP_DIR}${BACKUP_NAME}.${BACKUP_COUNT}" done # # Rotate the existing backups. Assume no change in permissions, etc. # set ${BACKUP_FILES} if [ "${1}" = "" ] ; then echo "${SCRIPT}: unexpected error in using backup list. Aborting." exit 0 fi OLDEST="${1}" NEXT="${1}" shift while [ "$1" != "" ] ; do NEXT="${1}" rm -f "${OLDEST}" "${OLDEST}.gz" if [ -f "${NEXT}" ] ; then ${MV} "${NEXT}" "${OLDEST}" elif [ -f "${NEXT}.gz" ] ; then ${MV} "${NEXT}.gz" "${OLDEST}.gz" else # <3> sb, 17.10.96: remove this pesky warning: #echo "${SCRIPT}: Missing backup log ${NEXT} or ${NEXT}.gz. Continuing." : fi OLDEST="${NEXT}" shift done # # Copy the current log to be the first backup. Use full pathnames # as appropriate. # if [ "${SOURCE_DIR}" != "" ] ; then if cd "${SOURCE_DIR}" ; then : else echo "${SCRIPT}: unexpected error in command 'cd ${SOURCE_DIR}'. Aborting." exit 0 fi fi rm -f "${NEXT}" "${NEXT}.gz" if [ "${CMD_BEFORE}" != "" ] ; then ${CMD_BEFORE} fi if ${MV} "${SOURCE_NAME}" "${NEXT}" ; then : else echo "${SCRIPT}: unexpected error making first backup. Aborting." exit 0 fi # Delete old log, create new empty one # MAke sure this happens before sending HUP to syslog <5> rm -f "${SOURCE_NAME}" "${SOURCE_NAME}".gz if cat > "${SOURCE_NAME}" < /dev/null ; then : else echo "${SCRIPT}: unexpected error emptying log file. Continuing." fi # # Set ownership and permission on the log as requested. # if [ "${SOURCE_MODE}" != "" ] ; then if ${CHMOD} ${SOURCE_MODE} "${SOURCE_NAME}" ; then : else echo "${SCRIPT}: unexpected error executing command '${CHMOD} ${SOURCE_MODE} ${SOURCE_NAME}'." echo "Aborting." exit 0 fi fi if [ "${SOURCE_OWNER}" != "" ] ; then if ${CHOWN} ${SOURCE_OWNER} "${SOURCE_NAME}" ; then : else echo "${SCRIPT}: unexpected error executing command '${CHOWN} ${SOURCE_OWNER} ${SOURCE_NAME}'." echo "Aborting." exit 0 fi fi if [ "${SOURCE_GROUP}" != "" ] ; then if ${CHGRP} ${SOURCE_GROUP} "${SOURCE_NAME}" ; then : else echo "${SCRIPT}: unexpected error executing command '${CHGRP} ${SOURCE_GROUP} ${SOURCE_NAME}'." echo "Aborting." exit 0 fi fi # Typically a HUP signal is sent to syslog here if [ "${CMD_AFTER}" != "" ] ; then ${CMD_AFTER} ## <4> if [ -f ${SOURCE_NAME}.offset ] ; then #echo "Reset logcheck offset" rm -f ${SOURCE_NAME}.offset fi fi # # Set ownerships and permissions as requested on the backed up log. # Note that the compress must come last in this sequence. # if [ "${BACKUP_MODE}" != "" ] ; then if ${CHMOD} ${BACKUP_MODE} "${NEXT}" ; then : else echo "${SCRIPT}: unexpected error executing command '${CHMOD} ${BACKUP_MODE} ${NEXT}'." echo "Aborting." exit 0 fi fi if [ "${BACKUP_OWNER}" != "" ] ; then if ${CHOWN} ${BACKUP_OWNER} "${NEXT}" ; then : else echo "${SCRIPT}: unexpected error executing command '${CHOWN} ${BACKUP_OWNER} ${NEXT}'." echo "Aborting." exit 0 fi fi if [ "${BACKUP_GROUP}" != "" ] ; then if ${CHGRP} ${BACKUP_GROUP} "${NEXT}" ; then : else echo "${SCRIPT}: unexpected error executing command '${CHGRP} ${BACKUP_GROUP} ${NEXT}'." echo "Aborting." exit 0 fi fi if [ "${COMPRESS}" != "" ] ; then if ${COMPRESS} "${NEXT}" ; then : else echo "${SCRIPT}: unexpected error executing command '${COMPRESS} ${NEXT}'." echo "Aborting." exit 0 fi fi #eof