Files
2026-05-20 15:23:05 +03:00

185 lines
4.7 KiB
Bash
Executable File

#!/bin/sh
set -e
SETPRIV="/bin/setpriv --reuid redis --regid redis --clear-groups"
IS_REDIS_SENTINEL=""
IS_REDIS_SERVER=""
CONFIG=""
SKIP_FIX_PERMS_NOTICE="Use SKIP_FIX_PERMS=1 to skip permission changes."
# functions
has_cap() {
/bin/setpriv -d | grep -q 'Capability bounding set:.*\b'"$1"'\b'
}
check_for_sentinel() {
CMD="$1"
shift
if [ "$CMD" = '/usr/local/bin/redis-server' ]; then
for arg in "$@"; do
if [ "$arg" = "--sentinel" ]; then
return 0
fi
done
fi
if [ "$CMD" = '/usr/local/bin/redis-sentinel' ]; then
return 0
fi
return 1
}
# Note: Change permissions only in simple, default cases to avoid affecting
# unexpected or user-specific files.
fix_data_dir_perms() {
# Expecting only *.rdb files and default appendonlydir; skip if others are found.
unknown_file="$(find . -mindepth 1 -maxdepth 1 \
-not \( -name \*.rdb -or \( -type d -and -name appendonlydir \) \) \
-print -quit)"
if [ -z "$unknown_file" ]; then
find . -print0 | fix_perms_and_owner rw
else
echo "Notice: Unknown file '$unknown_file' found in data dir. Permissions will not be modified. $SKIP_FIX_PERMS_NOTICE"
fi
}
fix_config_perms() {
config="$1"
mode="$2"
if [ ! -f "$config" ]; then
return 0
fi
confdir="$(dirname "$config")"
if [ ! -d "$confdir" ]; then
return 0
fi
# Expecting only the config file; skip if others are found.
pattern=$(printf "%s" "$(basename "$config")" | sed 's/[][?*]/\\&/g')
unknown_file=$(find "$confdir" -mindepth 1 -maxdepth 1 -not -name "$pattern" -print -quit)
if [ -z "$unknown_file" ]; then
printf '%s\0%s\0' "$confdir" "$config" | fix_perms_and_owner "$mode"
else
echo "Notice: Unknown file '$unknown_file' found in '$confdir'. Permissions will not be modified. $SKIP_FIX_PERMS_NOTICE"
fi
}
fix_perms_and_owner() {
mode="$1"
# shellcheck disable=SC3045
while IFS= read -r -d '' file; do
if [ "$mode" = "rw" ] && $SETPRIV test -r "$file" -a -w "$file"; then
continue
elif [ "$mode" = "r" ] && $SETPRIV test -r "$file"; then
continue
fi
new_mode=$mode
if [ -d "$file" ]; then
new_mode=${mode}x
fi
err=$(chown redis "$file" 2>&1) || echo "Warning: cannot change owner to 'redis' for '$file': $err. $SKIP_FIX_PERMS_NOTICE"
err=$(chmod "u+$new_mode" "$file" 2>&1) || echo "Warning: cannot change mode to 'u+$new_mode' for '$file': $err. $SKIP_FIX_PERMS_NOTICE"
done
}
# first arg is `-f` or `--some-option`
# or first arg is `something.conf`
if [ "${1#-}" != "$1" ] || [ "${1%.conf}" != "$1" ]; then
set -- redis-server "$@"
fi
CMD=$(command -v "$1" 2>/dev/null || :)
if [ "$(readlink -f "$CMD")" = '/usr/local/bin/redis-server' ]; then
IS_REDIS_SERVER=1
fi
if check_for_sentinel "$CMD" "$@"; then
IS_REDIS_SENTINEL=1
fi
# if is server and its first arg is not an option then it's a config
if [ "$IS_REDIS_SERVER" ] && [ "${2#-}" = "$2" ]; then
CONFIG="$2"
fi
# drop privileges only if
# we are starting either server or sentinel
# our uid is 0 (container started without explicit --user)
# and we have capabilities required to drop privs
if [ "$IS_REDIS_SERVER" ] && [ -z "$SKIP_DROP_PRIVS" ] && [ "$(id -u)" = '0' ] && has_cap setuid && has_cap setgid; then
if [ -z "$SKIP_FIX_PERMS" ]; then
# fix permissions
if [ "$IS_REDIS_SENTINEL" ]; then
fix_config_perms "$CONFIG" rw
else
fix_data_dir_perms
fix_config_perms "$CONFIG" r
fi
fi
CAPS_TO_KEEP=""
if has_cap sys_resource; then
# we have sys_resource capability, keep it available for redis
# as redis may use it to increase open files limit
CAPS_TO_KEEP=",+sys_resource"
fi
exec $SETPRIV \
--nnp \
--inh-caps=-all$CAPS_TO_KEEP \
--ambient-caps=-all$CAPS_TO_KEEP \
--bounding-set=-all$CAPS_TO_KEEP \
"$0" "$@"
fi
# set an appropriate umask (if one isn't set already)
# - https://github.com/docker-library/redis/issues/305
# - https://github.com/redis/redis/blob/bb875603fb7ff3f9d19aad906bd45d7db98d9a39/utils/systemd-redis_server.service#L37
um="$(umask)"
if [ "$um" = '0022' ]; then
umask 0077
fi
if [ "$IS_REDIS_SERVER" ] && ! [ "$IS_REDIS_SENTINEL" ]; then
echo "Starting Redis Server"
modules_dir="/usr/local/lib/redis/modules/"
if [ ! -d "$modules_dir" ]; then
echo "Warning: Default Redis modules directory $modules_dir does not exist."
elif [ -n "$(ls -A $modules_dir 2>/dev/null)" ]; then
for module in "$modules_dir"/*.so;
do
if [ ! -s "$module" ]; then
echo "Skipping module $module: file has no size."
continue
fi
if [ -d "$module" ]; then
echo "Skipping module $module: is a directory."
continue
fi
if [ ! -r "$module" ]; then
echo "Skipping module $module: file is not readable."
continue
fi
if [ ! -x "$module" ]; then
echo "Warning: Module $module is not executable."
continue
fi
set -- "$@" --loadmodule "$module"
done
fi
fi
exec "$@"