2023-05-13 17:03:50 +00:00
|
|
|
#!/bin/sh
|
|
|
|
|
|
|
|
# NAME:
|
|
|
|
# newlog - rotate log files
|
|
|
|
#
|
|
|
|
# SYNOPSIS:
|
|
|
|
# newlog.sh [options] "log"[:"num"] ...
|
|
|
|
#
|
|
|
|
# DESCRIPTION:
|
|
|
|
# This script saves multiple generations of each "log".
|
|
|
|
# The "logs" are kept compressed except for the current and
|
|
|
|
# previous ones.
|
|
|
|
#
|
|
|
|
# Options:
|
|
|
|
#
|
|
|
|
# -C "compress"
|
|
|
|
# Compact old logs (other than .0) with "compress"
|
|
|
|
# (default is 'gzip' or 'compress' if no 'gzip').
|
|
|
|
#
|
|
|
|
# -E "ext"
|
|
|
|
# If "compress" produces a file extention other than
|
|
|
|
# '.Z' or '.gz' we need to know.
|
|
|
|
#
|
|
|
|
# -G "gens"
|
|
|
|
# "gens" is a comma separated list of "log":"num" pairs
|
|
|
|
# that allows certain logs to handled differently.
|
|
|
|
#
|
|
|
|
# -N Don't actually do anything, just show us.
|
|
|
|
#
|
|
|
|
# -R Rotate rather than save logs by default.
|
|
|
|
# This is the default anyway.
|
|
|
|
#
|
|
|
|
# -S Save rather than rotate logs by default.
|
|
|
|
# Each log is saved to a unique name that remains
|
|
|
|
# unchanged. This results in far less churn.
|
|
|
|
#
|
|
|
|
# -f "fmt"
|
|
|
|
# Format ('%Y%m%d.%H%M%S') for suffix added to "log" to
|
|
|
|
# uniquely name it when using the '-S' option.
|
|
|
|
# If a "log" is saved more than once per second we add
|
|
|
|
# an extra suffix of our process-id.
|
|
|
|
#
|
|
|
|
# -d The "log" to be rotated/saved is a directory.
|
|
|
|
# We leave the mode of old directories alone.
|
|
|
|
#
|
|
|
|
# -e Normally logs are only cycled if non-empty, this
|
|
|
|
# option forces empty logs to be cycled as well.
|
|
|
|
#
|
|
|
|
# -g "group"
|
|
|
|
# Set the group of "log" to "group".
|
|
|
|
#
|
|
|
|
# -m "mode"
|
|
|
|
# Set the mode of "log".
|
|
|
|
#
|
|
|
|
# -M "mode"
|
|
|
|
# Set the mode of old logs (default 444).
|
|
|
|
#
|
|
|
|
# -n "num"
|
|
|
|
# Keep "num" generations of "log".
|
|
|
|
#
|
|
|
|
# -o "owner"
|
|
|
|
# Set the owner of "log".
|
|
|
|
#
|
|
|
|
# Regardless of whether '-R' or '-S' is provided, we attempt to
|
|
|
|
# choose the correct behavior based on observation of "log.0" if
|
|
|
|
# it exists; if it is a symbolic link, we save, otherwise
|
|
|
|
# we rotate.
|
|
|
|
#
|
|
|
|
# BUGS:
|
|
|
|
# 'Newlog.sh' tries to avoid being fooled by symbolic links, but
|
|
|
|
# multiply indirect symlinks are only handled on machines where
|
|
|
|
# test(1) supports a check for symlinks.
|
|
|
|
#
|
|
|
|
# AUTHOR:
|
|
|
|
# Simon J. Gerraty <sjg@crufty.net>
|
|
|
|
#
|
|
|
|
|
|
|
|
# RCSid:
|
Import bmake-20240309
Intersting/relevant changes since bmake-20240108
ChangeLog since bmake-20240108
2024-03-10 Simon J Gerraty <sjg@beast.crufty.net>
* boot-strap: tests can take a long time; use a cookie to
skip them if bmake has not been updated since tests last
ran successfully.
* Makefile: Cygwin handles MANTARGET man
* unit-tests/Makefile: set BROKEN_TESTS for Cygwin
2024-03-09 Simon J Gerraty <sjg@beast.crufty.net>
* VERSION (_MAKE_VERSION): 20240309
Merge with NetBSD make, pick up
o set .ERROR_EXIT to the exit status of .ERROR_TARGET
this allows a .ERROR target to ignore the case of
.ERROR_EXIT==6 which just means that the build actually
failed somewhere else.
2024-03-04 Simon J Gerraty <sjg@beast.crufty.net>
* VERSION (_MAKE_VERSION): 20240303
* var.c: on IRIX we need both inttypes.h and stdint.h
2024-03-01 Simon J Gerraty <sjg@beast.crufty.net>
* VERSION (_MAKE_VERSION): 20240301
Merge with NetBSD make, pick up
o export variables with value from target scope
when appropriate.
2024-02-12 Simon J Gerraty <sjg@beast.crufty.net>
* VERSION (_MAKE_VERSION): 20240212
Merge with NetBSD make, pick up
o remove unneeded conditional-compilation toggles
INCLUDES, LIBRARIES, POSIX, SYSVINCLUDE, SYSVVARSUB,
GMAKEEXPORT NO_REGEX and SUNSHCMD
* configure.in: add check for regex.h
* var.c: replace use of NO_REGEX with HAVE_REGEX_H
2024-02-04 Simon J Gerraty <sjg@beast.crufty.net>
* VERSION (_MAKE_VERSION): 20240204
Merge with NetBSD make, pick up
o var.c: fix some lint (-dL) mode parsing issues
2024-02-02 Simon J Gerraty <sjg@beast.crufty.net>
* VERSION: (_MAKE_VERSION): 20240202
Merge with NetBSD make, pick up
o make.1: note that arg to :D and :U can be empty
o var.c: $$ is not a parse error when .MAKE.SAVE_DOLLARS=no
mk/ChangeLog since bmake-20240108
2024-03-09 Simon J Gerraty <sjg@beast.crufty.net>
* install-mk (MK_VERSION): 20240309
* meta.sys.mk: _metaError: if .ERROR_EXIT == 6, we do not
want to save the .ERROR_META_FILE
2024-02-20 Simon J Gerraty <sjg@beast.crufty.net>
* install-mk (MK_VERSION): 20240220
* sys.dirdeps.mk, dirdeps-targets.mk, init.mk:
do not set .MAIN: dirdeps in sys.dirdeps.mk
dirdeps-targets.mk will do that for top-level builds
and init.mk will do it for others.
This allows a Makefile which has no need of 'dirdeps' to
set .MAIN for itself and "just work".
2024-02-18 Simon J Gerraty <sjg@beast.crufty.net>
* bsd.*.mk: for makefiles that get a bsd. symlink,
use _this in multiple inclusion tags since .PARSEFILE will not
DTRT when such a makefile is included directly by Makefile and
automatically (without bsd. prefix).
Since we cannot guarantee that our sys.mk will be used, we provide
a default _this in each makefile that gets a bsd. prefix such that
the value is the same regardless of bsd. prefix.
* subdir.mk: drop the !target guard on $SUBDIR_TARGETS
2024-02-12 Simon J Gerraty <sjg@beast.crufty.net>
* install-mk (MK_VERSION): 20240212
* SPDX-License-Identifier: BSD-2-Clause
Add SPDX-License-Identifier to inidicate that I consider
my copyright on any of these makefiles equivalent to BSD-2-Clause
* autoconf.mk: allow for configure.ac as currently recommended
* subdir.mk: support @auto
which is replaced with each subdir that
has a [Mm]akefile.
* subdir.mk: include local.subdir.mk if it exists.
* subdir.mk: rework to handle .WAIT
2024-02-11 Simon J Gerraty <sjg@beast.crufty.net>
* subdir.mk: _SUBDIRUSE report the target we are entering subdirs for.
2024-02-10 Simon J Gerraty <sjg@beast.crufty.net>
* prog.mk: treat empty SRCS the same as undefined
2024-02-02 Simon J Gerraty <sjg@beast.crufty.net>
* Avoid undefined errors in lint (-dL) mode
* man.mk (CMT2DOC_FLAGS): note that -mm does mdoc(7)
2024-01-28 Simon J Gerraty <sjg@beast.crufty.net>
* install-mk (MK_VERSION): 20240128
* FILES: add ccm.dep.mk for C++ modules
add suffixes.mk for common location for generic SUFFIX rules.
* auto.dep.mk autodep.mk meta.autodep.mk: include ccm.dep.mk
replace OBJ_EXTENSIONS with OBJ_SUFFIXES
* autodep.mk: leverage CXX_SUFFIXES for __depsrcs
and update style (spaces around = etc)
* init.mk: add OBJS_SRCS_FILTER to filter SRCS when
setting OBJS
* meta2deps.py: handle multiple ./ embedded in path better.
2024-03-14 02:14:41 +00:00
|
|
|
# $Id: newlog.sh,v 1.27 2024/02/17 17:26:57 sjg Exp $
|
|
|
|
#
|
|
|
|
# SPDX-License-Identifier: BSD-2-Clause
|
2023-05-13 17:03:50 +00:00
|
|
|
#
|
|
|
|
# @(#) Copyright (c) 1993-2016 Simon J. Gerraty
|
|
|
|
#
|
|
|
|
# This file is provided in the hope that it will
|
|
|
|
# be of use. There is absolutely NO WARRANTY.
|
|
|
|
# Permission to copy, redistribute or otherwise
|
|
|
|
# use this file is hereby granted provided that
|
|
|
|
# the above copyright notice and this notice are
|
|
|
|
# left intact.
|
|
|
|
#
|
|
|
|
# Please send copies of changes and bug-fixes to:
|
|
|
|
# sjg@crufty.net
|
|
|
|
#
|
|
|
|
|
|
|
|
Mydir=`dirname $0`
|
|
|
|
case $Mydir in
|
|
|
|
/*) ;;
|
|
|
|
*) Mydir=`cd $Mydir; pwd`;;
|
|
|
|
esac
|
|
|
|
|
|
|
|
# places to find chown (and setopts.sh)
|
|
|
|
PATH=$PATH:/usr/etc:/sbin:/usr/sbin:/usr/local/share/bin:/share/bin:$Mydir
|
|
|
|
|
|
|
|
# linux doesn't necessarily have compress,
|
|
|
|
# and gzip appears in various locations...
|
|
|
|
Which() {
|
|
|
|
case "$1" in
|
|
|
|
-*) t=$1; shift;;
|
|
|
|
*) t=-x;;
|
|
|
|
esac
|
|
|
|
case "$1" in
|
|
|
|
/*) test $t $1 && echo $1;;
|
|
|
|
*)
|
|
|
|
for d in `IFS=:; echo ${2:-$PATH}`
|
|
|
|
do
|
|
|
|
test $t $d/$1 && { echo $d/$1; break; }
|
|
|
|
done
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
|
|
|
# shell's typically have test(1) as built-in
|
|
|
|
# and not all support all options.
|
|
|
|
test_opt() {
|
|
|
|
_o=$1
|
|
|
|
_a=$2
|
|
|
|
_t=${3:-/}
|
|
|
|
|
|
|
|
case `test -$_o $_t 2>&1` in
|
|
|
|
*:*) eval test_$_o=$_a;;
|
|
|
|
*) eval test_$_o=-$_o;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
|
|
|
# convert find/ls mode to octal
|
|
|
|
fmode() {
|
|
|
|
eval `echo $1 |
|
|
|
|
sed 's,\(.\)\(...\)\(...\)\(...\),ft=\1 um=\2 gm=\3 om=\4,'`
|
|
|
|
sm=
|
|
|
|
case "$um" in
|
|
|
|
*s*) sm=r
|
|
|
|
um=`echo $um | sed 's,s,x,'`
|
|
|
|
;;
|
|
|
|
*) sm=-;;
|
|
|
|
esac
|
|
|
|
case "$gm" in
|
|
|
|
*[Ss]*)
|
|
|
|
sm=${sm}w
|
|
|
|
gm=`echo $gm | sed 's,s,x,;s,S,-,'`
|
|
|
|
;;
|
|
|
|
*) sm=${sm}-;;
|
|
|
|
esac
|
|
|
|
case "$om" in
|
|
|
|
*t)
|
|
|
|
sm=${sm}x
|
|
|
|
om=`echo $om | sed 's,t,x,'`
|
|
|
|
;;
|
|
|
|
*) sm=${sm}-;;
|
|
|
|
esac
|
|
|
|
echo $sm $um $gm $om |
|
|
|
|
sed 's,rwx,7,g;s,rw-,6,g;s,r-x,5,g;s,r--,4,g;s,-wx,3,g;s,-w-,2,g;s,--x,1,g;s,---,0,g;s, ,,g'
|
|
|
|
}
|
|
|
|
|
|
|
|
get_mode() {
|
|
|
|
case "$OS,$STAT" in
|
|
|
|
FreeBSD,*)
|
|
|
|
$STAT -f %Op $1 | sed 's,.*\(....\),\1,'
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
# fallback to find
|
|
|
|
fmode `find $1 -ls -prune | awk '{ print $3 }'`
|
|
|
|
}
|
|
|
|
|
|
|
|
get_mtime_suffix() {
|
|
|
|
case "$OS,$STAT" in
|
|
|
|
FreeBSD,*)
|
|
|
|
$STAT -t "${2:-$opt_f}" -f %Sm $1
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
# this will have to do
|
|
|
|
date "+${2:-$opt_f}"
|
|
|
|
}
|
|
|
|
|
|
|
|
case /$0 in
|
|
|
|
*/newlog*) rotate_func=rotate_log;;
|
|
|
|
*/save*) rotate_func=save_log;;
|
|
|
|
*) rotate_func=rotate_log;;
|
|
|
|
esac
|
|
|
|
|
|
|
|
opt_n=7
|
|
|
|
opt_m=
|
|
|
|
opt_M=444
|
|
|
|
opt_f=%Y%m%d.%H%M%S
|
|
|
|
opt_str=dNn:o:g:G:C:M:m:eE:f:RS
|
|
|
|
|
|
|
|
. setopts.sh
|
|
|
|
|
|
|
|
test $# -gt 0 || exit 0 # nothing to do.
|
|
|
|
|
|
|
|
OS=${OS:-`uname`}
|
|
|
|
STAT=${STAT:-`Which stat`}
|
|
|
|
|
|
|
|
# sorry, setops semantics for booleans changed.
|
|
|
|
case "${opt_d:-0}" in
|
|
|
|
0) rm_f=-f
|
|
|
|
opt_d=-f
|
|
|
|
for x in $opt_C gzip compress
|
|
|
|
do
|
|
|
|
opt_C=`Which $x "/bin:/usr/bin:$PATH"`
|
|
|
|
test -x $opt_C && break
|
|
|
|
done
|
|
|
|
empty() { test ! -s $1; }
|
|
|
|
;;
|
|
|
|
*) rm_f=-rf
|
|
|
|
opt_d=-d
|
|
|
|
opt_M=
|
|
|
|
opt_C=:
|
|
|
|
empty() {
|
|
|
|
if [ -d $1 ]; then
|
|
|
|
n=`'ls' -a1 $1/. | wc -l`
|
|
|
|
[ $n -gt 2 ] && return 1
|
|
|
|
fi
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
case "${opt_N:-0}" in
|
|
|
|
0) ECHO=;;
|
|
|
|
*) ECHO=echo;;
|
|
|
|
esac
|
|
|
|
case "${opt_e:-0}" in
|
|
|
|
0) force=;;
|
|
|
|
*) force=yes;;
|
|
|
|
esac
|
|
|
|
case "${opt_R:-0}" in
|
|
|
|
0) ;;
|
|
|
|
*) rotate_func=rotate_log;;
|
|
|
|
esac
|
|
|
|
case "${opt_S:-0}" in
|
|
|
|
0) ;;
|
|
|
|
*) rotate_func=save_log opt_S=;;
|
|
|
|
esac
|
|
|
|
|
|
|
|
# see whether test handles -h or -L
|
|
|
|
test_opt L -h
|
|
|
|
test_opt h ""
|
|
|
|
case "$test_L,$test_h" in
|
|
|
|
-h,) test_L= ;; # we don't support either!
|
|
|
|
esac
|
|
|
|
|
|
|
|
case "$test_L" in
|
|
|
|
"") # No, so this is about all we can do...
|
|
|
|
logs=`'ls' -ld $* | awk '{ print $NF }'`
|
|
|
|
;;
|
|
|
|
*) # it does
|
|
|
|
logs="$*"
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
|
|
|
|
read_link() {
|
|
|
|
case "$test_L" in
|
|
|
|
"") 'ls' -ld $1 | awk '{ print $NF }'; return;;
|
|
|
|
esac
|
|
|
|
if test $test_L $1; then
|
|
|
|
'ls' -ld $1 | sed 's,.*> ,,'
|
|
|
|
else
|
|
|
|
echo $1
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
# create the new log
|
|
|
|
new_log() {
|
|
|
|
log=$1
|
|
|
|
mode=$2
|
|
|
|
if test "x$opt_M" != x; then
|
|
|
|
$ECHO chmod $opt_M $log.0 2> /dev/null
|
|
|
|
fi
|
|
|
|
# someone may have managed to write to it already
|
|
|
|
# so don't truncate it.
|
|
|
|
case "$opt_d" in
|
|
|
|
-d) $ECHO mkdir -p $log;;
|
|
|
|
*) $ECHO touch $log;;
|
|
|
|
esac
|
|
|
|
# the order here matters
|
|
|
|
test "x$opt_o" = x || $ECHO chown $opt_o $log
|
|
|
|
test "x$opt_g" = x || $ECHO chgrp $opt_g $log
|
|
|
|
test "x$mode" = x || $ECHO chmod $mode $log
|
|
|
|
}
|
|
|
|
|
|
|
|
rotate_log() {
|
|
|
|
log=$1
|
|
|
|
n=${2:-$opt_n}
|
|
|
|
|
|
|
|
# make sure excess generations are trimmed
|
|
|
|
$ECHO rm $rm_f `echo $log.$n | sed 's/\([0-9]\)$/[\1-9]*/'`
|
|
|
|
|
|
|
|
mode=${opt_m:-`get_mode $log`}
|
|
|
|
while test $n -gt 0
|
|
|
|
do
|
|
|
|
p=`expr $n - 1`
|
|
|
|
if test -s $log.$p; then
|
|
|
|
$ECHO rm $rm_f $log.$p.*
|
|
|
|
$ECHO $opt_C $log.$p
|
|
|
|
if test "x$opt_M" != x; then
|
|
|
|
$ECHO chmod $opt_M $log.$p.* 2> /dev/null
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
for ext in $opt_E .gz .Z ""
|
|
|
|
do
|
|
|
|
test $opt_d $log.$p$ext || continue
|
|
|
|
$ECHO mv $log.$p$ext $log.$n$ext
|
|
|
|
done
|
|
|
|
n=$p
|
|
|
|
done
|
|
|
|
# leave $log.0 uncompressed incase some one still has it open.
|
|
|
|
$ECHO mv $log $log.0
|
|
|
|
new_log $log $mode
|
|
|
|
}
|
|
|
|
|
|
|
|
# unlike rotate_log we do not rotate files,
|
|
|
|
# but give each log a unique (but stable name).
|
|
|
|
# This avoids churn for folk who rsync things.
|
|
|
|
# We make log.0 a symlink to the most recent log
|
|
|
|
# so it can be found and compressed next time around.
|
|
|
|
save_log() {
|
|
|
|
log=$1
|
|
|
|
n=${2:-$opt_n}
|
|
|
|
fmt=$3
|
|
|
|
|
|
|
|
last=`read_link $log.0`
|
|
|
|
case "$last" in
|
|
|
|
$log.0) # should never happen
|
|
|
|
test -s $last && $ECHO mv $last $log.$$;;
|
|
|
|
$log.*)
|
|
|
|
$ECHO $opt_C $last
|
|
|
|
;;
|
|
|
|
*.*) $ECHO $opt_C `dirname $log`/$last
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
$ECHO rm -f $log.0
|
|
|
|
# remove excess logs - we rely on mtime!
|
|
|
|
$ECHO rm $rm_f `'ls' -1td $log.* 2> /dev/null | sed "1,${n}d"`
|
|
|
|
|
|
|
|
mode=${opt_m:-`get_mode $log`}
|
|
|
|
# this is our default suffix
|
|
|
|
opt_S=${opt_S:-`get_mtime_suffix $log $fmt`}
|
|
|
|
case "$fmt" in
|
|
|
|
""|$opt_f) suffix=$opt_S;;
|
|
|
|
*) suffix=`get_mtime_suffix $log $fmt`;;
|
|
|
|
esac
|
|
|
|
|
|
|
|
# find a unique name to save current log as
|
|
|
|
for nlog in $log.$suffix $log.$suffix.$$
|
|
|
|
do
|
|
|
|
for f in $nlog*
|
|
|
|
do
|
|
|
|
break
|
|
|
|
done
|
|
|
|
test $opt_d $f || break
|
|
|
|
done
|
|
|
|
# leave $log.0 uncompressed incase some one still has it open.
|
|
|
|
$ECHO mv $log $nlog
|
|
|
|
test "x$opt_M" = x || $ECHO chmod $opt_M $nlog 2> /dev/null
|
|
|
|
$ECHO ln -s `basename $nlog` $log.0
|
|
|
|
new_log $log $mode
|
|
|
|
}
|
|
|
|
|
|
|
|
for f in $logs
|
|
|
|
do
|
|
|
|
n=$opt_n
|
|
|
|
save=
|
|
|
|
case "$f" in
|
|
|
|
*:[1-9]*)
|
|
|
|
set -- `IFS=:; echo $f`; f=$1; n=$2;;
|
|
|
|
*:n=*|*:save=*)
|
|
|
|
eval `echo "f=$f" | tr ':' ' '`;;
|
|
|
|
esac
|
|
|
|
# try and pick the right function to use
|
|
|
|
rfunc=$rotate_func # default
|
|
|
|
if test $opt_d $f.0; then
|
|
|
|
case `read_link $f.0` in
|
|
|
|
$f.0) rfunc=rotate_log;;
|
|
|
|
*) rfunc=save_log;;
|
|
|
|
esac
|
|
|
|
fi
|
|
|
|
case "$test_L" in
|
|
|
|
-?)
|
|
|
|
while test $test_L $f # it is [still] a symlink
|
|
|
|
do
|
|
|
|
f=`read_link $f`
|
|
|
|
done
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
case ",${opt_G}," in
|
|
|
|
*,${f}:n=*|,${f}:save=*)
|
|
|
|
eval `echo ",${opt_G}," | sed "s!.*,${f}:\([^,]*\),.*!\1!;s,:, ,g"`
|
|
|
|
;;
|
|
|
|
*,${f}:*)
|
|
|
|
# opt_G is a , separated list of log:n pairs
|
|
|
|
n=`echo ,$opt_G, | sed -e "s,.*${f}:\([0-9][0-9]*\).*,\1,"`
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
|
|
|
|
if empty $f; then
|
|
|
|
test "$force" || continue
|
|
|
|
fi
|
|
|
|
|
|
|
|
test "$save" && rfunc=save_log
|
|
|
|
|
|
|
|
$rfunc $f $n $save
|
|
|
|
done
|