You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ublinux-init/ublinux/rc.preinit.d/24-logging

293 lines
19 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#!/usr/bin/env bash
#
# Author: Dmitry Razumov <asmeron@ublinux.com>
# Copyright (c) 2021-2025 UBLinux <support@ublinux.com>
#
# Initial script for Linux UBLinux
# This script are launching before starting init from initrd script
# Current dir allways must be set to root (/)
# All system path must be relative, except initrd dirs
ENABLED=yes
[[ ${ENABLED} == "yes" ]] || exit 0
DEBUGMODE=no
PATH=.:/:/usr/bin:/usr/local/bin:/usr/local/sbin
[[ -d /usr/lib/ublinux ]] && { ROOTFS= ; CMD_CHROOT= ; } || { [[ -d /sysroot ]] && ROOTFS="/sysroot" || ROOTFS="."; CMD_CHROOT="chroot ${ROOTFS}"; }
SOURCE=${ROOTFS}/usr/lib/ublinux/functions; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null || exit 0
SOURCE=${ROOTFS}/usr/lib/ublinux/default; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null || exit 0
debug_mode "$0" "$@"
SYSCONF="${ROOTFS}${SYSCONF}"
SOURCE=${SYSCONF}/config; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null
SOURCE=${SYSCONF}/logging; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null
## Настройка мониторинга и сбора системных событий и записи их в журналы для аудита
## AUDITD=disable|no|none|off # Отключить все созданные правила из конфигурации
## AUDITD[<id_name>]=<rule>
## <id_name> # Уникальное имя правила
## <rule> # Правило
#AUDITD[event_chmod]="-a always,exit -F arch=x86_64 -S chmod,fchmod,fchmodat -F key=event_chmod"
#AUDITD[passwd_changes]="-w /etc/passwd -p wa -k passwd_changes"
exec_auditd(){
[[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && COMMAND=$1 && shift
[[ -n ${COMMAND} ]] || COMMAND="set="
FILE_PATTERN_AUDITD_CONF="${ROOTFS}/etc/audit/rules.d/00-ubconfig.rules"
local PARAM="$@"
if [[ -n ${PARAM} ]]; then
AUDITD_NAME=${PARAM%%=*}
AUDITD_VAR=${PARAM#*=}
fi
[[ -d ${FILE_PATTERN_AUDITD_CONF%/*} ]] || mkdir -p ${FILE_PATTERN_AUDITD_CONF%/*}
[[ -f ${FILE_PATTERN_AUDITD_CONF} ]] || true > "${FILE_PATTERN_AUDITD_CONF}"
if [[ -z ${PARAM} ]]; then
true > "${FILE_PATTERN_AUDITD_CONF}"
while IFS='=' read -u3 AUDITD_NAME AUDITD_VAR; do
[[ ${AUDITD_NAME} =~ ^.*'['(.*)']' ]] && AUDITD_NAME=${BASH_REMATCH[1]}
[[ ${AUDITD_VAR} =~ ^\"(.*)\"$ ]] && AUDITD_VAR=${BASH_REMATCH[1]}
echo "${AUDITD_VAR}" >> "${FILE_PATTERN_AUDITD_CONF}"
done 3< <(grep -E "^[[:space:]]*AUDITD\[" ${SYSCONF}/logging 2>/dev/null)
elif [[ ${COMMAND} == @("set="|"set+="|"set++=") ]]; then
[[ ${AUDITD_NAME} =~ ^.*'['(.*)']' ]] && AUDITD_NAME=${BASH_REMATCH[1]}
[[ ${AUDITD_VAR} =~ ^\"(.*)\"$ ]] && AUDITD_VAR=${BASH_REMATCH[1]}
echo "${AUDITD_VAR}" >> "${FILE_PATTERN_AUDITD_CONF}"
elif [[ ${COMMAND} == @("set-="|"set--="|"remove") ]]; then
if [[ -n ${AUDITD_NAME} && ${AUDITD_VAR} != "" ]]; then
[[ ${AUDITD_NAME} =~ ^.*'['(.*)']' ]] && AUDITD_NAME=${BASH_REMATCH[1]}
AUDITD_VAR=${AUDITD[${AUDITD_NAME}]}
fi
[[ ${AUDITD_VAR} =~ ^\"(.*)\"$ ]] && AUDITD_VAR=${BASH_REMATCH[1]}
ESC_AUDITD_VAR=$(sed 's/[^a-zA-Z0-9=",_@#%&<> -]/\\&/g' <<< "${AUDITD_VAR}")
sed "/^${ESC_AUDITD_VAR}$/d" -i "${FILE_PATTERN_AUDITD_CONF}"
fi
}
exec_auditd_live(){
[[ -z ${ROOTFS} ]] || return 0
SERVICE_NAME="auditd.service"
if [[ $(pgrep -fc "exec_audit_live") == 1 ]]; then
if systemctl --quiet is-enabled ${SERVICE_NAME} 2>/dev/null; then
sleep 5
systemctl --quiet reset-failed ${SERVICE_NAME}
systemctl --quiet restart ${SERVICE_NAME} 2>/dev/null
fi
fi
}
## Настройка журналов
## https://www.freedesktop.org/software/systemd/man/journald.conf.html
## JOURNALD[<var>]=<value>
## <var> # Имя переменной настройки журнала
## Storage # Указывает, где хранить журнал. Доступны следующие параметры:
## # "volatile" - Журнал хранится в оперативной памяти, т.е. в каталоге /run/log/journal
## # "persistent" - Данные хранятся на диске, т.е. в каталоге /var/log/journal
## # "auto" - используется по-умолчанию
## # "none" - Журнал не ведётся
## Compress # Пороговое значение данных для сжатия и записи в ФС. Может принимать yes, no, цифра. Суффиксы, такие как K, M и G
## SplitMode # Определяет, следует ли разделять файлы журнала для каждого пользователя: «uid» или «none»
## RateLimitIntervalSec # Настраивает ограничение скорости, которое применяется ко всем сообщениям, интервал времени применения =30
## RateLimitBurst # Настраивает ограничение скорости, которое применяется ко всем сообщениям, лимит сообщений =10000
## SystemMaxUse # Указывает максимальное дисковое пространство, которое может использовать журнал в постоянном хранилище
## SystemKeepFree # Указывает объем места, которое журнал должен оставить свободным при добавлении записей журнала в постоянное хранилище
## SystemMaxFileSize # Определяет, до какого размера могут вырасти отдельные файлы журнала в постоянном хранилище перед ротацией
## RuntimeMaxUse # Указывает максимальное дисковое пространство, которое можно использовать в энергозависимом хранилище (в файловой системе /run)
## RuntimeKeepFree # Указывает объем пространства, которое будет выделено для других целей при записи данных в энергозависимое хранилище (в файловой системе /run)
## RuntimeMaxFileSize # Указывает объем места, которое отдельный файл журнала может занимать в энергозависимом хранилище (в файловой системе /run) перед ротацией
## ForwardToConsole # Перенаправить журнал на консоль, yes|no
## TTYPath # Измените используемый консольный TTY, если используется ForwardToConsole=yes. По умолчанию /dev/console.
## MaxLevelConsole # Тип сообщений перенаправляемые в журнал, варианты: emerg|alert|crit|err|warning|notice|info|debug или целочисленные значения в диапазоне 07
## <value> # Значение переменной настройки журнала
#JOURNALD[Storage]=persistent
#JOURNALD[Compress]=yes
#JOURNALD[SystemMaxUse]=8M
#JOURNALD[RuntimeMaxUse]=8M
exec_journald(){
[[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && COMMAND=$1 && shift
[[ -n ${COMMAND} ]] || COMMAND="set="
FILE_JOURNALD_CONF="${ROOTFS}/etc/systemd/journald.conf.d/00-ubconfig.conf"
local PARAM="$@"
if [[ -n ${PARAM} ]]; then
local JOURNALD=
declare -A JOURNALD
[[ ${PARAM%%=*} =~ [!\$%\&()*+,/\;\<\=\>?\^\{|\}~] ]] || eval "${PARAM%%=*}=\${PARAM#*=}"
fi
[[ ! -f ${FILE_JOURNALD_CONF} ]] && mkdir -p "${FILE_JOURNALD_CONF%/*}" && touch ${FILE_JOURNALD_CONF}
[[ $(cat ${FILE_JOURNALD_CONF}) =~ "[Journal]" ]] || echo "[Journal]" > ${FILE_JOURNALD_CONF}
if [[ ${COMMAND} == @("set="|"set+="|"set++=") ]] && [[ ${#JOURNALD[@]} != 0 ]]; then
while IFS= read -u3 NAME_VAR; do
if [[ $(cat ${FILE_JOURNALD_CONF}) =~ "${NAME_VAR}=" ]]; then
sed "s/^${NAME_VAR}=.*/${NAME_VAR}=${JOURNALD[${NAME_VAR}]}/g" -i ${FILE_JOURNALD_CONF}
else
echo "${NAME_VAR}=${JOURNALD[${NAME_VAR}]}" >> ${FILE_JOURNALD_CONF}
fi
done 3< <(printf "%s\n" "${!JOURNALD[@]}")
elif [[ ${COMMAND} == @("set-="|"set--="|"remove") ]]; then
if [[ ${PARAM%%=*} =~ ^.*'['(.*)']' ]]; then
NAME_VAR=${BASH_REMATCH[1]}
sed "/${NAME_VAR}=/d" -i ${FILE_JOURNALD_CONF}
fi
fi
}
exec_journald_live(){
[[ -z ${ROOTFS} ]] || return 0
SERVICE_NAME="systemd-journald.service"
if [[ $(pgrep -fc "exec_journald_live") == 1 ]]; then
sleep 5
systemctl reset-failed ${SERVICE_NAME}
systemctl --quiet restart ${SERVICE_NAME}
fi
}
## Настройка дампа ядра
## https://www.freedesktop.org/software/systemd/man/latest/systemd-coredump.html
## SYSTEMD_COREDUMP[<var>]=<value>
## <var> # Имя переменной настройки журнала
## Storage # Указывает, где хранить дамп ядра. Доступны следующие параметры:
## journal # Дампы будут храниться в журнале и перезаписываться в соответствии со стандартными принципами ротации журналов
## external # Значение по умолчанию, дампы сохраняются в каталоге /var/lib/systemd/coredump/
## none # Дампы ядра записываются (включая обратную трассировку, если возможно), но не сохраняются
## Compress # Используется для сжатия дампов ядра. Принимает логический аргумент - *yes или no
## *yes # Дампы сжимаются при сохранении (значение по умолчанию)
## no # Дампы сохраняются без сжатия.
## ProcessSizeMax # Максимальный размер дампа процесса, который может быть сохранен. Если размер дампа превышает значение этого параметра, то дамп сохранен не будет. Суфиксы: B
## # Параметры Storage=none и ProcessSizeMax=0 отключает всю обработку дампа памяти, за исключением записи журнала
## ExternalSizeMax # Максимальный (сжатый или несжатый) размер дампа процесса, который будет сохранен на диске
## JournalSizeMax # Максимальный (сжатый или несжатый) размер дампа процесса, который будет сохранен в журнале системы
## MaxUse # Максимальный объем общего дискового пространства, который может быть использован для хранения дампов процессов. Суфиксы: B,K,M,G,T,P,E
## KeepFree # Минимальный объем свободного дискового пространства, который должен оставаться на диске при хранении дампов. Суфиксы: B,K,M,G,T,P,E
## <value> # Значение переменной настройки журнала
#SYSTEMD_COREDUMP[Storage]=none
#SYSTEMD_COREDUMP[ProcessSizeMax]=0
exec_systemd_coredump(){
[[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && COMMAND=$1 && shift
[[ -n ${COMMAND} ]] || COMMAND="set="
FILE_SYSTEMD_COREDUMP_CONF="${ROOTFS}/etc/systemd/coredump.conf.d/00-ubconfig.conf"
local PARAM="$@"
if [[ -n ${PARAM} ]]; then
local SYSTEMD_COREDUMP=
declare -A SYSTEMD_COREDUMP
[[ ${PARAM%%=*} =~ [!\$%\&()*+,/\;\<\=\>?\^\{|\}~] ]] || eval "${PARAM%%=*}=\${PARAM#*=}"
fi
[[ ! -f ${FILE_SYSTEMD_COREDUMP_CONF} ]] && mkdir -p "${FILE_SYSTEMD_COREDUMP_CONF%/*}" && touch ${FILE_SYSTEMD_COREDUMP_CONF}
[[ $(cat ${FILE_SYSTEMD_COREDUMP_CONF}) =~ "[Coredump]" ]] || echo "[Coredump]" > ${FILE_SYSTEMD_COREDUMP_CONF}
if [[ ${COMMAND} == @("set="|"set+="|"set++=") ]] && [[ ${#SYSTEMD_COREDUMP[@]} != 0 ]]; then
while IFS= read -u3 NAME_VAR; do
if [[ $(cat ${FILE_SYSTEMD_COREDUMP_CONF}) =~ "${NAME_VAR}=" ]]; then
sed "s/^${NAME_VAR}=.*/${NAME_VAR}=${SYSTEMD_COREDUMP[${NAME_VAR}]}/g" -i ${FILE_SYSTEMD_COREDUMP_CONF}
else
echo "${NAME_VAR}=${SYSTEMD_COREDUMP[${NAME_VAR}]}" >> ${FILE_SYSTEMD_COREDUMP_CONF}
fi
done 3< <(printf "%s\n" "${!SYSTEMD_COREDUMP[@]}")
elif [[ ${COMMAND} == @("set-="|"set--="|"remove") ]]; then
if [[ ${PARAM%%=*} =~ ^.*'['(.*)']' ]]; then
NAME_VAR=${BASH_REMATCH[1]}
sed "/${NAME_VAR}=/d" -i ${FILE_SYSTEMD_COREDUMP_CONF}
fi
fi
}
## Настройка ротации файлов логов утилитой logrotate
## https://man.archlinux.org/man/logrotate.conf.5
## LOGROTATE[<tag>]="<mask_file_1>,<mask_file_2>,<mask_file_n>:<setting_1>,<setting_2>,<setting_n>"
#LOGROTATE[samba]="/var/log/samba/log.smbd,/var/log/samba/log.nmbd,/var/log/samba/*.log:notifempty,missingok,copytruncate"
#LOGROTATE[chrony]="/var/log/chrony/*.log:missingok,nocreate,sharedscripts,postrotate,/usr/bin/chronyc cyclelogs > /dev/null 2>&1 || true,endscript"
#LOGROTATE[clamav]="/var/log/clamav/clamd.log,/var/log/clamav/freshclam.log,/var/log/clamav/clamav-milter.log:create 644 clamav clamav,sharedscripts,missingok,notifempty,postrotate,/bin/kill -HUP \`cat /run/clamav/clamd.pid 2>/dev/null\` 2> /dev/null || true,/bin/kill -HUP \`cat /run/clamav/freshclam.pid 2>/dev/null\` 2> /dev/null || true,/bin/kill -HUP \`cat /run/clamav/clamav-milter.pid 2>/dev/null\` 2> /dev/null || true,endscript"
exec_logrotate(){
[[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && COMMAND=$1 && shift
[[ -n ${COMMAND} ]] || COMMAND="set="
FILE_PATTERN_LOGROTATE_CONF="${ROOTFS}/etc/logrotate.d/ubconfig-"
local PARAM="$@"
if [[ -n ${PARAM} ]]; then
local LOGROTATE=
declare -A LOGROTATE
[[ ${PARAM%%=*} =~ [!\$%\&()*+,/\;\<\=\>?\^\{|\}~] ]] || eval "${PARAM%%=*}=\${PARAM#*=}"
fi
[[ -d ${FILE_PATTERN_LOGROTATE_CONF%/*} ]] || mkdir -p ${PATH_LOGROTATE_CONF%/*}
if [[ ${COMMAND} == "set=" ]] && [[ ${#LOGROTATE[@]} != 0 ]]; then
while IFS= read -u3 NAME_FILE; do
FILES_LOG="${LOGROTATE[${NAME_FILE}]%%:*}"; FILES_LOG="${FILES_LOG//,/ }"
RULES_LOG="${LOGROTATE[${NAME_FILE}]#*:}"
TAB_COUNT='\t'
# Вставляем список файлов логов
echo "${FILES_LOG} {" > "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}"
# Вставляем правила для вращения логов
while IFS= read -r SELECT_RULES_LOG; do
[[ ${SELECT_RULES_LOG} == "endscript" ]] && TAB_COUNT='\t'
echo -e "${TAB_COUNT}${SELECT_RULES_LOG}" >> "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}"
[[ ${SELECT_RULES_LOG} == "postrotate" ]] && TAB_COUNT='\t\t'
done < <(tr ',' '\n' <<< ${RULES_LOG})
echo "}" >> "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}"
done 3< <(printf "%s\n" "${!LOGROTATE[@]}")
elif [[ ${COMMAND} == @("set+="|"set++=") ]] && [[ ${#LOGROTATE[@]} != 0 ]]; then
while IFS= read -u3 NAME_FILE; do
[[ -f ${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE} ]] || return 0
FILES_LOG="${LOGROTATE[${NAME_FILE}]%%:*}"
RULES_LOG="${LOGROTATE[${NAME_FILE}]#*:}"
[[ ${FILES_LOG} == ${RULES_LOG} ]] && unset RULES_LOG
FILES_LOG="${FILES_LOG//,/ }"
# Вставить в список файлов последним
[[ -n ${FILES_LOG} ]] && ESC_FILES_LOG=$(sed 's/[^a-zA-Z0-9=",_@#%&<> -]/\\&/g' <<< "${FILES_LOG}")
[[ -n ${FILES_LOG} ]] && [[ ! $(cat "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}") =~ ${FILES_LOG} ]] \
&& sed -E "0,/ \{/s/ \{/ ${ESC_FILES_LOG} \{/" -i "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}"
# Вставить в список правил последним
[[ -n ${RULES_LOG} ]] && ESC_RULES_LOG=$(sed 's/[^a-zA-Z0-9=",_@#%&<> -]/\\&/g' <<< "${RULES_LOG}")
[[ -n ${RULES_LOG} ]] && [[ ! $(cat "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}") =~ ${RULES_LOG} ]] \
&& sed -E "/^\}$/i\\\t${ESC_RULES_LOG}" -i "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}"
done 3< <(printf "%s\n" "${!LOGROTATE[@]}")
elif [[ ${COMMAND} == @("set-="|"set--=") ]]; then
while IFS= read -u3 NAME_FILE; do
FILES_LOG="${LOGROTATE[${NAME_FILE}]%%:*}"
RULES_LOG="${LOGROTATE[${NAME_FILE}]#*:}"
[[ ${FILES_LOG} == ${RULES_LOG} ]] && unset RULES_LOG
FILES_LOG="${FILES_LOG//,/ }"
# Если удаляемая часть относится к файлу, то просто вырезать, если к тексту, то удалить строку
[[ -n ${FILES_LOG} ]] && ESC_FILES_LOG=$(sed 's/[^a-zA-Z0-9=",_@#%&<> -]/\\&/g' <<< "${FILES_LOG}")
[[ -n ${FILES_LOG} ]] && [[ $(cat "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}") =~ ${FILES_LOG} ]] \
&& sed -E "0,/ \{/s/${ESC_FILES_LOG}//" -i "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}"
[[ -n ${RULES_LOG} ]] && ESC_RULES_LOG=$(sed 's/[^a-zA-Z0-9=",_@#%&<> -]/\\&/g' <<< "${RULES_LOG}")
[[ -n ${RULES_LOG} ]] && [[ $(cat "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}") =~ ${RULES_LOG} ]] \
&& sed "/${ESC_RULES_LOG}/d" -i "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}"
done 3< <(printf "%s\n" "${!LOGROTATE[@]}")
elif [[ ${COMMAND} == "remove" ]]; then
while IFS= read -u3 NAME_FILE; do
[[ -f ${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE} ]] || return 0
rm -f "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}"
done 3< <(printf "%s\n" "${!LOGROTATE[@]}")
fi
}
# Применить ротцию принудительно на указанный файл
# $1 # Имя переменной с файлом, пример: LOGROTATE[clamav]
exec_logrotate_live(){
[[ -z ${ROOTFS} ]] || return 0
NAME_FILE=$1
[[ ${NAME_FILE%%=*} =~ ^.*'['(.*)']' ]] && NAME_FILE=${BASH_REMATCH[1]}
[[ -n ${NAME_FILE} ]] || return 0
FILE_PATTERN_LOGROTATE_CONF="${ROOTFS}/etc/logrotate.d/ubconfig-"
if [[ $(pgrep -fc "exec_logrotate_live") == 1 ]]; then
sleep 2
logrotate -f "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}"
fi
}
################
##### MAIN #####
################
# Если файл подключен как ресурс с функциями, то выйти
return 0 2>/dev/null && return 0
if [[ -z $@ ]]; then
while read -r FUNCTION; do
$"${FUNCTION##* }"
done < <(declare -F | grep "declare -f exec_")
else
FUNCTION=
while [[ $# -gt 0 ]]; do
[[ -z ${1} ]] || { declare -f ${1} &>/dev/null && FUNCTION+="; ${1}" || FUNCTION+=" '${1}'"; }
shift
done
eval ${FUNCTION#*; }
fi