Version 0.2.2.

Remove -g option as it was broken and would never work.
Open and read from file descriptor for input rather than keep accessing a file.
Re-worked code around the user changing facility - it now actually works \o/.
Minor tweeks to the help text.
This commit is contained in:
Darren 'Tadgy' Austin 2020-06-14 16:03:43 +01:00
commit 1adf0ee2b9

View file

@ -8,7 +8,7 @@
# Script details. # Script details.
NAME="${0##*/}" NAME="${0##*/}"
VERSION="0.2.1" VERSION="0.2.2"
# Functions. # Functions.
@ -86,12 +86,6 @@ display_help() {
-f Request flushing of the log file to disk after every write. -f Request flushing of the log file to disk after every write.
This may significantly reduce performance and result in a lot of This may significantly reduce performance and result in a lot of
disk writes. Best to let the kernel do appropriate buffering. disk writes. Best to let the kernel do appropriate buffering.
-g <group> Set name of the group to run with. Override the usual
behaviour of using the primary group membership of the user
specified with -u and run with this GID. Log files created by
lumberjack will be owned by this group. The default is to run
with the primary group that executed lumberjack, which is
usually root. This option is only available to root.
-h Display this help. -h Display this help.
-i <pipe> Read input from the pipe/FIFO at <pipe>, rather than stdin. -i <pipe> Read input from the pipe/FIFO at <pipe>, rather than stdin.
If the pipe/FIFO does not exist, it will be created. Use '-o' If the pipe/FIFO does not exist, it will be created. Use '-o'
@ -112,7 +106,7 @@ display_help() {
-mp <umask> Set the umask used when creating the pipe. Default: $PIPE_UMASK. -mp <umask> Set the umask used when creating the pipe. Default: $PIPE_UMASK.
Useful umasks are: 066 and 006. Useful umasks are: 066 and 006.
-o <owner> Set the owner of the pipe/FIFO automatically created if none -o <owner> Set the owner of the pipe/FIFO automatically created if none
already exists, and -i is used. The <owner> should be in the already exists, and '-i' is used. The <owner> should be in the
format [user]:[group], where [user] or [group] is optional, but format [user]:[group], where [user] or [group] is optional, but
not both. The ownership is changed before any user or group not both. The ownership is changed before any user or group
switching is performed. This option is only available to root. switching is performed. This option is only available to root.
@ -130,12 +124,11 @@ display_help() {
<basedir> and <template>. <basedir> and <template>.
-s <facility> Set the syslog facility to be used for logging. Default: $SYSLOG_FACILITY. -s <facility> Set the syslog facility to be used for logging. Default: $SYSLOG_FACILITY.
-u <user> Set name of the user to run with. With this option, as soon as -u <user> Set name of the user to run with. With this option, as soon as
lumberjack starts it will re-exec itself, running as this user. $NAME starts it will re-exec itself to run as this user.
Without the -g option, the primary group of <user> is used for Log files created by $NAME will be owned by this user and
the running GID. Log files created by lumberjack will be owned its primary group. The default is to run as the user that
by this user. The default is to run as the user that executed executed $NAME, which is usually root. This option is
lumberjack, which is usually root. This option is only only available to root.
available to root.
-v Display version and copyright information. -v Display version and copyright information.
-z Enable compression of the old log files. -z Enable compression of the old log files.
-- Cease option processing and begin argument parsing. -- Cease option processing and begin argument parsing.
@ -151,8 +144,8 @@ display_help() {
template may also include any %-prefixed format strings template may also include any %-prefixed format strings
recognised by the strftime(3) function. See below for examples. recognised by the strftime(3) function. See below for examples.
The template can not start with a / - it is relative to the The template can not start with a / - it is relative to the
<basedir>. Unless the -p option is used, all directories up to <basedir>. Unless the '-p' option is used, all directories up
- but not including - the first directory with non-escaped to - but not including - the first directory with non-escaped
%-format strings of the <template> must already exist for the %-format strings of the <template> must already exist for the
log lines to be written to the file. log lines to be written to the file.
@ -190,6 +183,8 @@ EOF
} }
exit_handler() { exit_handler() {
(( INPUTFD != 0 )) && { exec {INPUTFD}>&-; } 2>/dev/null
(( FLAGS[created-fifo] == 1 )) && { (( FLAGS[created-fifo] == 1 )) && {
rm -f "$INPUT" 2>/dev/null || syslog "warn" "failed to remove pipe/fifo: $INPUT" rm -f "$INPUT" 2>/dev/null || syslog "warn" "failed to remove pipe/fifo: $INPUT"
} }
@ -341,7 +336,8 @@ ORIG_ARGS=()
# Some detaults. # Some detaults.
COMPRESSOR_ARGS=( "-9" ) COMPRESSOR_ARGS=( "-9" )
COMPRESSOR="gzip" # Use gzip by default as log processing utils can often natively read gzipped files. COMPRESSOR="gzip" # Use gzip by default as log processing utils can often natively read gzipped files.
INPUT="/dev/stdin" INPUT=""
INPUTFD="0"
MAXJOBS="4" MAXJOBS="4"
LINKFILE="" LINKFILE=""
DIR_UMASK="022" DIR_UMASK="022"
@ -350,7 +346,6 @@ PIPE_UMASK="066"
PIPE_OWNER="" PIPE_OWNER=""
SYSLOG_FACILITY="user" SYSLOG_FACILITY="user"
RUNAS_USER="" RUNAS_USER=""
RUNAS_GROUP=""
FLAGS=([flush]=0 [raw]=0 [compress]=0 [make-parents]=0 [created-fifo]=0 [timed-out]=0 [basedir-vanished]=0 [basedir-notdir]=0) FLAGS=([flush]=0 [raw]=0 [compress]=0 [make-parents]=0 [created-fifo]=0 [timed-out]=0 [basedir-vanished]=0 [basedir-notdir]=0)
# trap signals. # trap signals.
@ -387,14 +382,6 @@ while :; do
shift shift
continue continue
;; ;;
-g)
# Set the group to run as.
(( UID != 0 )) && die "only root can use -g"
getent group "$2" >/dev/null 2>&1 || die "invalid group given for -g: $2"
RUNAS_GROUP="$2"
shift 2
continue
;;
-h|-help|--help) -h|-help|--help)
# Show the help screen and exit. # Show the help screen and exit.
display_help display_help
@ -534,7 +521,7 @@ TEMPLATE="$2"
[[ "${BASEDIR:0:1}" != "/" ]] && die "must be an absolute path: $BASEDIR" [[ "${BASEDIR:0:1}" != "/" ]] && die "must be an absolute path: $BASEDIR"
[[ ! -e "$BASEDIR" ]] && die "base directory does not exist: $BASEDIR" [[ ! -e "$BASEDIR" ]] && die "base directory does not exist: $BASEDIR"
[[ ! -d "$BASEDIR" ]] && die "not a directory: $BASEDIR" [[ ! -d "$BASEDIR" ]] && die "not a directory: $BASEDIR"
[[ ! -w "$BASEDIR" ]] && die "no write permission: $BASEDIR" (( "${FLAGS[make-parents]}" == 1 )) && [[ ! -w "$BASEDIR" ]] && die "no write permission: $BASEDIR"
[[ "${TEMPLATE: 0:1}" == "/" ]] && die "template cannot start with '/' - must be a relative path: $TEMPLATE" [[ "${TEMPLATE: 0:1}" == "/" ]] && die "template cannot start with '/' - must be a relative path: $TEMPLATE"
[[ "${TEMPLATE: -1:1}" == "/" ]] && die "template cannot end with '/' - path must be a filename: $TEMPLATE" [[ "${TEMPLATE: -1:1}" == "/" ]] && die "template cannot end with '/' - path must be a filename: $TEMPLATE"
(( FLAGS[raw] == 0 )) && [[ ! "$TEMPLATE" =~ .*\{\} ]] && die "template must include at least one '{}': $TEMPLATE" (( FLAGS[raw] == 0 )) && [[ ! "$TEMPLATE" =~ .*\{\} ]] && die "template must include at least one '{}': $TEMPLATE"
@ -542,7 +529,7 @@ TEMPLATE="$2"
(( FLAGS[raw] != 0 )) && [[ "$LINKFILE" =~ .*\{\} ]] && die "link name cannot include '{}': $LINKFILE" (( FLAGS[raw] != 0 )) && [[ "$LINKFILE" =~ .*\{\} ]] && die "link name cannot include '{}': $LINKFILE"
# If input is to be a pipe/FIFO, create it if necessary. # If input is to be a pipe/FIFO, create it if necessary.
[[ "$INPUT" != "/dev/stdin" ]] && { [[ -n "$INPUT" ]] && {
if [[ ! -e "$INPUT" ]]; then if [[ ! -e "$INPUT" ]]; then
umask "$PIPE_UMASK" umask "$PIPE_UMASK"
mkfifo "$INPUT" 2>/dev/null || die "failed to create pipe/FIFO: $INPUT" mkfifo "$INPUT" 2>/dev/null || die "failed to create pipe/FIFO: $INPUT"
@ -553,20 +540,12 @@ TEMPLATE="$2"
fi fi
} }
# Apply user and group settings. # Apply user and setting.
# shellcheck disable=SC2093 # shellcheck disable=SC2093
if [[ -n "$RUNAS_USER" ]]; then [[ -n "$RUNAS_USER" ]] && { exec -a "su" /bin/su - "$RUNAS_USER" -- "$0" "${ORIG_ARGS[@]}" "$BASEDIR" "$TEMPLATE" || die "failed to exec to change user"; }
if [[ -n "$RUNAS_GROUP" ]]; then
exec su -g "$RUNAS_GROUP" -- "$RUNAS_USER" "$0" "${ORIG_ARGS[@]}" "$BASEDIR" "$TEMPLATE" # If input is to be a pipe/FIFO, open it.
die "failed to exec to change user and group" [[ -n "$INPUT" ]] && { exec {INPUTFD}<"$INPUT" || die "failed to open pipe/FIFO for reading: $INPUT"; }
else
exec su -- "$RUNAS_USER" "$@" "${ORIG_ARGS[@]}" "$BASEDIR" "$TEMPLATE"
die "failed to exec to change user"
fi
elif [[ -n "$RUNAS_GROUP" ]]; then
exec sg -- "$RUNAS_GROUP" "$0" "${ORIG_ARGS[@]}"
die "failed to exec to change group"
fi
# Main loop # Main loop
while :; do while :; do
@ -587,7 +566,7 @@ while :; do
# Note: The $(...) expansion should *not* be quoted in this instance, and the space between # Note: The $(...) expansion should *not* be quoted in this instance, and the space between
# $( and (( is necessary to quiet shellcheck. # $( and (( is necessary to quiet shellcheck.
# shellcheck disable=SC2046 # shellcheck disable=SC2046
read -r -t "$TTNM" $( (( FLAGS[raw] == 0 )) && printf "%s" "LOG_VHOST") LOG_DATA <"$INPUT" read -r -t "$TTNM" -u "$INPUTFD" $( (( FLAGS[raw] == 0 )) && printf "%s" "LOG_VHOST") LOG_DATA
ERR="$?" ERR="$?"
# Determine how the read above was exited. # Determine how the read above was exited.
@ -595,7 +574,7 @@ while :; do
# If 'read' timed out, set a marker. # If 'read' timed out, set a marker.
FLAGS[timed-out]=1 FLAGS[timed-out]=1
elif (( ERR == 1 )); then elif (( ERR == 1 )); then
[[ "$INPUT" == "/dev/stdin" ]] && { (( INPUTFD == 0 )) && {
# stdin has been closed by the parent, quit gracefully by raising a SIGTERM. # stdin has been closed by the parent, quit gracefully by raising a SIGTERM.
kill -TERM "$$" kill -TERM "$$"
} }