From 88cc9d112a9d1db4c84ba81dced2b0764a110e69 Mon Sep 17 00:00:00 2001 From: spa77k <254093522+spa77k@users.noreply.github.com> Date: Mon, 2 Nov 2026 21:54:44 +0900 Subject: [PATCH] Split log4j and JVM flags handling out of start-finalExec (#4372) --- scripts/start-finalExec | 337 +------------------------------ scripts/start-finalExec-jvmFlags | 206 +++++++++++++++++++ scripts/start-finalExec-log4j | 130 ++++++++++++ 3 files changed, 340 insertions(+), 333 deletions(-) create mode 100755 scripts/start-finalExec-jvmFlags create mode 100755 scripts/start-finalExec-log4j diff --git a/scripts/start-finalExec b/scripts/start-finalExec index 475f7930..c41b5de1 100755 --- a/scripts/start-finalExec +++ b/scripts/start-finalExec @@ -65,66 +65,11 @@ if [ -n "$ICON" ]; then fi fi -useGeneratedLogs=${GENERATE_LOG4J2_CONFIG:-${ENABLE_ROLLING_LOGS:-false}} -useFallbackJvmFlag=false - SERVER_DIR="$baseDataDir" if [[ ${FTB_DIR:-} ]]; then SERVER_DIR="$FTB_DIR" fi - -patchLog4jConfig() { - file=${1?} - url=${2?} - if ! get -o "${SERVER_DIR}/${file}" "$url"; then - logError "Failed to download corrected log4j config, fallback to JVM flag" - useFallbackJvmFlag=true - return 1 - fi - JVM_OPTS="-Dlog4j.configurationFile=${file} ${JVM_OPTS}" - useGeneratedLogs=false -} - -# Temporarily disable debugging output -oldState=$(shopt -po xtrace || true) -shopt -u -o xtrace -# Patch Log4j remote code execution vulnerability -# See https://www.minecraft.net/en-us/article/important-message--security-vulnerability-java-edition -if isFamily NATIVE; then - : # Native server, so there is no log4j to patch -elif versionLessThan 1.7; then - : # No patch required here. -elif isFamily VANILLA && versionLessThan 1.12; then - patchLog4jConfig log4j2_17-111.xml https://launcher.mojang.com/v1/objects/dd2b723346a8dcd48e7f4d245f6bf09e98db9696/log4j2_17-111.xml -elif isFamily VANILLA && versionLessThan 1.17; then - patchLog4jConfig log4j2_112-116.xml https://launcher.mojang.com/v1/objects/02937d122c86ce73319ef9975b58896fc1b491d1/log4j2_112-116.xml -# See https://purpurmc.org/docs/Log4j/ -elif isType PURPUR && versionLessThan 1.17; then - patchLog4jConfig purpur_log4j2_1141-1165.xml https://purpurmc.org/docs/xml/purpur_log4j2_1141-1165.xml -elif isType PURPUR && versionLessThan 1.18.1; then - patchLog4jConfig purpur_log4j2_117.xml https://purpurmc.org/docs/xml/purpur_log4j2_117.xml -elif versionLessThan 1.18.1; then - useFallbackJvmFlag=true -fi -eval "$oldState" - -if ${useFallbackJvmFlag}; then - JVM_OPTS="-Dlog4j2.formatMsgNoLookups=true ${JVM_OPTS}" -fi - -if isFamily NATIVE; then - : # Native server, so no Log4jPatcher agent -elif versionLessThan 1.7; then - : # No patch required here. -elif versionLessThan 1.18.1; then - if isTrue "${SKIP_LOG4J_PATCHER:-false}"; then - log "Skipping Log4jPatcher, make sure you are not affected" - else - JVM_OPTS="-javaagent:/image/Log4jPatcher.jar ${JVM_OPTS}" - fi -fi - function addAgents() { local agents=$1 outDir=$2 glob=$3 option=$4 @@ -158,80 +103,8 @@ else fi fi -# Set up log4j2 configuration with templating support -LOGFILE="${SERVER_DIR}/log4j2.xml" -if isFamily NATIVE; then - : # Native server, so no log4j configuration -elif ${useGeneratedLogs}; then - # Set up log configuration defaults - : "${LOG_LEVEL:=info}" - : "${ROLLING_LOG_MAX_FILES:=1000}" - # Note: Can't use ${VAR:=default} syntax for values containing } as it breaks parsing - if [ -z "${ROLLING_LOG_FILE_PATTERN}" ]; then - ROLLING_LOG_FILE_PATTERN='logs/%d{yyyy-MM-dd}-%i.log.gz' - fi - - # Pattern format defaults (compatible with vanilla Minecraft) - # Note: Can't use ${VAR:=default} syntax because } in the value breaks parsing - if [ -z "${LOG_CONSOLE_FORMAT}" ]; then - LOG_CONSOLE_FORMAT='[%d{HH:mm:ss}] [%t/%level]: %msg%n' - fi - if [ -z "${LOG_TERMINAL_FORMAT}" ]; then - LOG_TERMINAL_FORMAT='[%d{HH:mm:ss} %level]: %msg%n' - fi - if [ -z "${LOG_FILE_FORMAT}" ]; then - LOG_FILE_FORMAT='[%d{HH:mm:ss}] [%t/%level]: %msg%n' - fi - - export LOG_LEVEL ROLLING_LOG_FILE_PATTERN ROLLING_LOG_MAX_FILES - export LOG_CONSOLE_FORMAT LOG_TERMINAL_FORMAT LOG_FILE_FORMAT - - - # Always regenerate if file doesn't exist - if [ ! -e "$LOGFILE" ] || isTrue "${REGENERATE_LOG4J2:-true}"; then - log "Generating log4j2.xml from template in ${LOGFILE}" - - # Generate log4j2.xml using heredoc for reliable variable substitution - cat > "$LOGFILE" < - - - - - - - - - - - - - - - - - - - - - - - - - - - - -EOF - else - log "log4j2.xml already exists and is up to date, skipping generation" - fi - - # Apply the log4j2 configuration - JVM_OPTS="-Dlog4j.configurationFile=log4j2.xml ${JVM_OPTS}" -else - rm -f "${LOGFILE}" -fi +# shellcheck source=start-finalExec-log4j +. "$(dirname "$0")/start-finalExec-log4j" # Optional disable console if ! isFamily NATIVE && versionLessThan 1.14 && [[ ${CONSOLE,,} = false ]]; then @@ -265,210 +138,8 @@ if isTrue "${ENABLE_JMX}"; then log "JMX is enabled. Make sure you have port forwarding for ${JMX_PORT}" fi -: "${USE_AIKAR_FLAGS:=false}" -: "${USE_MEOWICE_FLAGS:=false}" -: "${USE_MEOWICE_GRAALVM_FLAGS:=false}" - -if isTrue "${USE_MEOWICE_FLAGS}" || isTrue "${USE_MEOWICE_GRAALVM_FLAGS}"; then - java_major_version=$(mc-image-helper java-release) -fi - -if isTrue "${USE_MEOWICE_FLAGS}"; then - if [[ $java_major_version -gt 16 ]]; then - log "Java version $java_major_version using MeowIce's flags for Java 17+" - else - log "Your Java version is $java_major_version, MeowIce's flags are for Java 17+ falling back to Aikar's" - USE_MEOWICE_FLAGS=FALSE - USE_AIKAR_FLAGS=TRUE - fi -fi - -if isTrue "${USE_AIKAR_FLAGS}" || isTrue "${USE_MEOWICE_FLAGS}"; then - # From https://mcflags.emc.gs/ - if isTrue "${USE_MEOWICE_FLAGS}"; then - log "Using MeowIce's flags" - G1NewSizePercent=28 - G1MaxNewSizePercent=50 - G1HeapRegionSize=16M - G1ReservePercent=15 - InitiatingHeapOccupancyPercent=20 - G1MixedGCCountTarget=3 - G1RSetUpdatingPauseTimePercent=0 - elif [[ $MAX_MEMORY ]] && (( $(normalizeMemSize "${MAX_MEMORY}") >= $(normalizeMemSize 12g) )); then - log "Using Aikar's >12GB flags" - G1NewSizePercent=40 - G1MaxNewSizePercent=50 - G1HeapRegionSize=16M - G1ReservePercent=15 - InitiatingHeapOccupancyPercent=20 - G1MixedGCCountTarget=4 - G1RSetUpdatingPauseTimePercent=5 - else - log "Using Aikar's flags" - G1NewSizePercent=30 - G1MaxNewSizePercent=40 - G1HeapRegionSize=8M - G1ReservePercent=20 - InitiatingHeapOccupancyPercent=15 - G1MixedGCCountTarget=4 - G1RSetUpdatingPauseTimePercent=5 - fi - - JVM_XX_OPTS="${JVM_XX_OPTS} - -XX:+UseG1GC - -XX:+ParallelRefProcEnabled - -XX:MaxGCPauseMillis=200 - -XX:+UnlockExperimentalVMOptions - -XX:+DisableExplicitGC - -XX:+AlwaysPreTouch - -XX:G1NewSizePercent=${G1NewSizePercent} - -XX:G1MaxNewSizePercent=${G1MaxNewSizePercent} - -XX:G1HeapRegionSize=${G1HeapRegionSize} - -XX:G1ReservePercent=${G1ReservePercent} - -XX:G1HeapWastePercent=5 - -XX:G1MixedGCCountTarget=${G1MixedGCCountTarget} - -XX:InitiatingHeapOccupancyPercent=${InitiatingHeapOccupancyPercent} - -XX:G1MixedGCLiveThresholdPercent=90 - -XX:G1RSetUpdatingPauseTimePercent=${G1RSetUpdatingPauseTimePercent} - -XX:SurvivorRatio=32 - -XX:+PerfDisableSharedMem - -XX:MaxTenuringThreshold=1 - " - if isTrue "${USE_AIKAR_FLAGS}"; then - JVM_XX_OPTS="${JVM_XX_OPTS} - -Dusing.aikars.flags=https://mcflags.emc.gs - -Daikars.new.flags=true - " - fi -fi - -if isTrue "${USE_MEOWICE_FLAGS}"; then - JVM_XX_OPTS="${JVM_XX_OPTS} - -XX:+UnlockDiagnosticVMOptions - -XX:+UnlockExperimentalVMOptions - -XX:G1SATBBufferEnqueueingThresholdPercent=30 - -XX:G1ConcMarkStepDurationMillis=5 - -XX:+UseNUMA - -XX:-DontCompileHugeMethods - -XX:MaxNodeLimit=240000 - -XX:NodeLimitFudgeFactor=8000 - -XX:ReservedCodeCacheSize=400M - -XX:NonNMethodCodeHeapSize=12M - -XX:ProfiledCodeHeapSize=194M - -XX:NonProfiledCodeHeapSize=194M - -XX:NmethodSweepActivity=1 - -XX:+UseFastUnorderedTimeStamps - -XX:+UseCriticalJavaThreadPriority - -XX:AllocatePrefetchStyle=3 - -XX:+AlwaysActAsServerClassMachine - -XX:+UseTransparentHugePages - -XX:LargePageSizeInBytes=2M - -XX:+UseLargePages - -XX:+EagerJVMCI - -XX:+UseStringDeduplication - -XX:+UseAES - -XX:+UseAESIntrinsics - -XX:+UseFMA - -XX:+UseLoopPredicate - -XX:+RangeCheckElimination - -XX:+OptimizeStringConcat - -XX:+UseCompressedOops - -XX:+UseThreadPriorities - -XX:+OmitStackTraceInFastThrow - -XX:+RewriteBytecodes - -XX:+RewriteFrequentPairs - -XX:+UseFPUForSpilling - -XX:+UseVectorCmov - -XX:+UseXMMForArrayCopy - -XX:+EliminateLocks - -XX:+DoEscapeAnalysis - -XX:+AlignVector - -XX:+OptimizeFill - -XX:+EnableVectorSupport - -XX:+UseCharacterCompareIntrinsics - -XX:+UseCopySignIntrinsic - -XX:+UseVectorStubs - " - if [[ $(arch) == "x86_64" ]]; then - JVM_XX_OPTS="${JVM_XX_OPTS} - -XX:+UseFastStosb - -XX:+UseNewLongLShift - -XX:+UseXmmI2D - -XX:+UseXmmI2F - -XX:+UseXmmLoadAndClearUpper - -XX:+UseXmmRegToRegMoveAll - -XX:UseAVX=2 - -XX:UseSSE=4 - " - else - log "cpu not x86_64, disabling architecture specific flags" - fi - if [[ $java_major_version -gt 23 ]]; then - JVM_XX_OPTS="${JVM_XX_OPTS} - -XX:+UseCompactObjectHeaders - " - fi -fi - -if isTrue "${USE_MEOWICE_GRAALVM_FLAGS}"; then - if [[ $java_major_version -gt 23 ]]; then - log "Java 24 or higher detected, using modified GraalVM flags" - JVM_XX_OPTS="${JVM_XX_OPTS} - -XX:+UseFastJNIAccessors - -XX:+UseInlineCaches - -XX:+SegmentedCodeCache - -Djdk.nio.maxCachedBufferSize=262144 - -Djdk.graal.UsePriorityInlining=true - -Djdk.graal.Vectorization=true - -Djdk.graal.OptDuplication=true - -Djdk.graal.DetectInvertedLoopsAsCounted=true - -Djdk.graal.LoopInversion=true - -Djdk.graal.VectorizeHashes=true - -Djdk.graal.EnterprisePartialUnroll=true - -Djdk.graal.VectorizeSIMD=true - -Djdk.graal.StripMineNonCountedLoops=true - -Djdk.graal.SpeculativeGuardMovement=true - -Djdk.graal.TuneInlinerExploration=1 - -Djdk.graal.LoopRotation=true - -Djdk.graal.CompilerConfiguration=enterprise - " - else - log "Using MeowIce's flags for Graalvm" - JVM_XX_OPTS="${JVM_XX_OPTS} - -XX:+UseFastJNIAccessors - -XX:+UseInlineCaches - -XX:+SegmentedCodeCache - -Djdk.nio.maxCachedBufferSize=262144 - -Dgraal.UsePriorityInlining=true - -Dgraal.Vectorization=true - -Dgraal.OptDuplication=true - -Dgraal.DetectInvertedLoopsAsCounted=true - -Dgraal.LoopInversion=true - -Dgraal.VectorizeHashes=true - -Dgraal.EnterprisePartialUnroll=true - -Dgraal.VectorizeSIMD=true - -Dgraal.StripMineNonCountedLoops=true - -Dgraal.SpeculativeGuardMovement=true - -Dgraal.TuneInlinerExploration=1 - -Dgraal.LoopRotation=true - -Dgraal.OptWriteMotion=true - -Dgraal.CompilerConfiguration=enterprise - " - fi -fi - -if isTrue "${USE_FLARE_FLAGS}"; then - JVM_XX_OPTS="${JVM_XX_OPTS} - -XX:+UnlockDiagnosticVMOptions - -XX:+DebugNonSafepoints - " -fi - -if isTrue "${USE_SIMD_FLAGS}"; then - JVM_XX_OPTS="${JVM_XX_OPTS} - --add-modules=jdk.incubator.vector - " -fi +# shellcheck source=start-finalExec-jvmFlags +. "$(dirname "$0")/start-finalExec-jvmFlags" # Handle GTNH args if isType "GTNH"; then diff --git a/scripts/start-finalExec-jvmFlags b/scripts/start-finalExec-jvmFlags new file mode 100755 index 00000000..842fb49f --- /dev/null +++ b/scripts/start-finalExec-jvmFlags @@ -0,0 +1,206 @@ +#!/bin/bash + +: "${USE_AIKAR_FLAGS:=false}" +: "${USE_MEOWICE_FLAGS:=false}" +: "${USE_MEOWICE_GRAALVM_FLAGS:=false}" + +if isTrue "${USE_MEOWICE_FLAGS}" || isTrue "${USE_MEOWICE_GRAALVM_FLAGS}"; then + java_major_version=$(mc-image-helper java-release) +fi + +if isTrue "${USE_MEOWICE_FLAGS}"; then + if [[ $java_major_version -gt 16 ]]; then + log "Java version $java_major_version using MeowIce's flags for Java 17+" + else + log "Your Java version is $java_major_version, MeowIce's flags are for Java 17+ falling back to Aikar's" + USE_MEOWICE_FLAGS=FALSE + USE_AIKAR_FLAGS=TRUE + fi +fi + +if isTrue "${USE_AIKAR_FLAGS}" || isTrue "${USE_MEOWICE_FLAGS}"; then + # From https://mcflags.emc.gs/ + if isTrue "${USE_MEOWICE_FLAGS}"; then + log "Using MeowIce's flags" + G1NewSizePercent=28 + G1MaxNewSizePercent=50 + G1HeapRegionSize=16M + G1ReservePercent=15 + InitiatingHeapOccupancyPercent=20 + G1MixedGCCountTarget=3 + G1RSetUpdatingPauseTimePercent=0 + elif [[ $MAX_MEMORY ]] && (( $(normalizeMemSize "${MAX_MEMORY}") >= $(normalizeMemSize 12g) )); then + log "Using Aikar's >12GB flags" + G1NewSizePercent=40 + G1MaxNewSizePercent=50 + G1HeapRegionSize=16M + G1ReservePercent=15 + InitiatingHeapOccupancyPercent=20 + G1MixedGCCountTarget=4 + G1RSetUpdatingPauseTimePercent=5 + else + log "Using Aikar's flags" + G1NewSizePercent=30 + G1MaxNewSizePercent=40 + G1HeapRegionSize=8M + G1ReservePercent=20 + InitiatingHeapOccupancyPercent=15 + G1MixedGCCountTarget=4 + G1RSetUpdatingPauseTimePercent=5 + fi + + JVM_XX_OPTS="${JVM_XX_OPTS} + -XX:+UseG1GC + -XX:+ParallelRefProcEnabled + -XX:MaxGCPauseMillis=200 + -XX:+UnlockExperimentalVMOptions + -XX:+DisableExplicitGC + -XX:+AlwaysPreTouch + -XX:G1NewSizePercent=${G1NewSizePercent} + -XX:G1MaxNewSizePercent=${G1MaxNewSizePercent} + -XX:G1HeapRegionSize=${G1HeapRegionSize} + -XX:G1ReservePercent=${G1ReservePercent} + -XX:G1HeapWastePercent=5 + -XX:G1MixedGCCountTarget=${G1MixedGCCountTarget} + -XX:InitiatingHeapOccupancyPercent=${InitiatingHeapOccupancyPercent} + -XX:G1MixedGCLiveThresholdPercent=90 + -XX:G1RSetUpdatingPauseTimePercent=${G1RSetUpdatingPauseTimePercent} + -XX:SurvivorRatio=32 + -XX:+PerfDisableSharedMem + -XX:MaxTenuringThreshold=1 + " + if isTrue "${USE_AIKAR_FLAGS}"; then + JVM_XX_OPTS="${JVM_XX_OPTS} + -Dusing.aikars.flags=https://mcflags.emc.gs + -Daikars.new.flags=true + " + fi +fi + +if isTrue "${USE_MEOWICE_FLAGS}"; then + JVM_XX_OPTS="${JVM_XX_OPTS} + -XX:+UnlockDiagnosticVMOptions + -XX:+UnlockExperimentalVMOptions + -XX:G1SATBBufferEnqueueingThresholdPercent=30 + -XX:G1ConcMarkStepDurationMillis=5 + -XX:+UseNUMA + -XX:-DontCompileHugeMethods + -XX:MaxNodeLimit=240000 + -XX:NodeLimitFudgeFactor=8000 + -XX:ReservedCodeCacheSize=400M + -XX:NonNMethodCodeHeapSize=12M + -XX:ProfiledCodeHeapSize=194M + -XX:NonProfiledCodeHeapSize=194M + -XX:NmethodSweepActivity=1 + -XX:+UseFastUnorderedTimeStamps + -XX:+UseCriticalJavaThreadPriority + -XX:AllocatePrefetchStyle=3 + -XX:+AlwaysActAsServerClassMachine + -XX:+UseTransparentHugePages + -XX:LargePageSizeInBytes=2M + -XX:+UseLargePages + -XX:+EagerJVMCI + -XX:+UseStringDeduplication + -XX:+UseAES + -XX:+UseAESIntrinsics + -XX:+UseFMA + -XX:+UseLoopPredicate + -XX:+RangeCheckElimination + -XX:+OptimizeStringConcat + -XX:+UseCompressedOops + -XX:+UseThreadPriorities + -XX:+OmitStackTraceInFastThrow + -XX:+RewriteBytecodes + -XX:+RewriteFrequentPairs + -XX:+UseFPUForSpilling + -XX:+UseVectorCmov + -XX:+UseXMMForArrayCopy + -XX:+EliminateLocks + -XX:+DoEscapeAnalysis + -XX:+AlignVector + -XX:+OptimizeFill + -XX:+EnableVectorSupport + -XX:+UseCharacterCompareIntrinsics + -XX:+UseCopySignIntrinsic + -XX:+UseVectorStubs + " + if [[ $(arch) == "x86_64" ]]; then + JVM_XX_OPTS="${JVM_XX_OPTS} + -XX:+UseFastStosb + -XX:+UseNewLongLShift + -XX:+UseXmmI2D + -XX:+UseXmmI2F + -XX:+UseXmmLoadAndClearUpper + -XX:+UseXmmRegToRegMoveAll + -XX:UseAVX=2 + -XX:UseSSE=4 + " + else + log "cpu not x86_64, disabling architecture specific flags" + fi + if [[ $java_major_version -gt 23 ]]; then + JVM_XX_OPTS="${JVM_XX_OPTS} + -XX:+UseCompactObjectHeaders + " + fi +fi + +if isTrue "${USE_MEOWICE_GRAALVM_FLAGS}"; then + if [[ $java_major_version -gt 23 ]]; then + log "Java 24 or higher detected, using modified GraalVM flags" + JVM_XX_OPTS="${JVM_XX_OPTS} + -XX:+UseFastJNIAccessors + -XX:+UseInlineCaches + -XX:+SegmentedCodeCache + -Djdk.nio.maxCachedBufferSize=262144 + -Djdk.graal.UsePriorityInlining=true + -Djdk.graal.Vectorization=true + -Djdk.graal.OptDuplication=true + -Djdk.graal.DetectInvertedLoopsAsCounted=true + -Djdk.graal.LoopInversion=true + -Djdk.graal.VectorizeHashes=true + -Djdk.graal.EnterprisePartialUnroll=true + -Djdk.graal.VectorizeSIMD=true + -Djdk.graal.StripMineNonCountedLoops=true + -Djdk.graal.SpeculativeGuardMovement=true + -Djdk.graal.TuneInlinerExploration=1 + -Djdk.graal.LoopRotation=true + -Djdk.graal.CompilerConfiguration=enterprise + " + else + log "Using MeowIce's flags for Graalvm" + JVM_XX_OPTS="${JVM_XX_OPTS} + -XX:+UseFastJNIAccessors + -XX:+UseInlineCaches + -XX:+SegmentedCodeCache + -Djdk.nio.maxCachedBufferSize=262144 + -Dgraal.UsePriorityInlining=true + -Dgraal.Vectorization=true + -Dgraal.OptDuplication=true + -Dgraal.DetectInvertedLoopsAsCounted=true + -Dgraal.LoopInversion=true + -Dgraal.VectorizeHashes=true + -Dgraal.EnterprisePartialUnroll=true + -Dgraal.VectorizeSIMD=true + -Dgraal.StripMineNonCountedLoops=true + -Dgraal.SpeculativeGuardMovement=true + -Dgraal.TuneInlinerExploration=1 + -Dgraal.LoopRotation=true + -Dgraal.OptWriteMotion=true + -Dgraal.CompilerConfiguration=enterprise + " + fi +fi + +if isTrue "${USE_FLARE_FLAGS}"; then + JVM_XX_OPTS="${JVM_XX_OPTS} + -XX:+UnlockDiagnosticVMOptions + -XX:+DebugNonSafepoints + " +fi + +if isTrue "${USE_SIMD_FLAGS}"; then + JVM_XX_OPTS="${JVM_XX_OPTS} + --add-modules=jdk.incubator.vector + " +fi diff --git a/scripts/start-finalExec-log4j b/scripts/start-finalExec-log4j new file mode 100755 index 00000000..75f9c529 --- /dev/null +++ b/scripts/start-finalExec-log4j @@ -0,0 +1,130 @@ +#!/bin/bash + +useGeneratedLogs=${GENERATE_LOG4J2_CONFIG:-${ENABLE_ROLLING_LOGS:-false}} +useFallbackJvmFlag=false + +patchLog4jConfig() { + file=${1?} + url=${2?} + if ! get -o "${SERVER_DIR}/${file}" "$url"; then + logError "Failed to download corrected log4j config, fallback to JVM flag" + useFallbackJvmFlag=true + return 1 + fi + JVM_OPTS="-Dlog4j.configurationFile=${file} ${JVM_OPTS}" + useGeneratedLogs=false +} + +# Temporarily disable debugging output +oldState=$(shopt -po xtrace || true) +shopt -u -o xtrace +# Patch Log4j remote code execution vulnerability +# See https://www.minecraft.net/en-us/article/important-message--security-vulnerability-java-edition +if isFamily NATIVE; then + : # Native server, so there is no log4j to patch +elif versionLessThan 1.7; then + : # No patch required here. +elif isFamily VANILLA && versionLessThan 1.12; then + patchLog4jConfig log4j2_17-111.xml https://launcher.mojang.com/v1/objects/dd2b723346a8dcd48e7f4d245f6bf09e98db9696/log4j2_17-111.xml +elif isFamily VANILLA && versionLessThan 1.17; then + patchLog4jConfig log4j2_112-116.xml https://launcher.mojang.com/v1/objects/02937d122c86ce73319ef9975b58896fc1b491d1/log4j2_112-116.xml +# See https://purpurmc.org/docs/Log4j/ +elif isType PURPUR && versionLessThan 1.17; then + patchLog4jConfig purpur_log4j2_1141-1165.xml https://purpurmc.org/docs/xml/purpur_log4j2_1141-1165.xml +elif isType PURPUR && versionLessThan 1.18.1; then + patchLog4jConfig purpur_log4j2_117.xml https://purpurmc.org/docs/xml/purpur_log4j2_117.xml +elif versionLessThan 1.18.1; then + useFallbackJvmFlag=true +fi +eval "$oldState" + +if ${useFallbackJvmFlag}; then + JVM_OPTS="-Dlog4j2.formatMsgNoLookups=true ${JVM_OPTS}" +fi + +if isFamily NATIVE; then + : # Native server, so no Log4jPatcher agent +elif versionLessThan 1.7; then + : # No patch required here. +elif versionLessThan 1.18.1; then + if isTrue "${SKIP_LOG4J_PATCHER:-false}"; then + log "Skipping Log4jPatcher, make sure you are not affected" + else + JVM_OPTS="-javaagent:/image/Log4jPatcher.jar ${JVM_OPTS}" + fi +fi + +# Set up log4j2 configuration with templating support +LOGFILE="${SERVER_DIR}/log4j2.xml" +if isFamily NATIVE; then + : # Native server, so no log4j configuration +elif ${useGeneratedLogs}; then + # Set up log configuration defaults + : "${LOG_LEVEL:=info}" + : "${ROLLING_LOG_MAX_FILES:=1000}" + # Note: Can't use ${VAR:=default} syntax for values containing } as it breaks parsing + if [ -z "${ROLLING_LOG_FILE_PATTERN}" ]; then + ROLLING_LOG_FILE_PATTERN='logs/%d{yyyy-MM-dd}-%i.log.gz' + fi + + # Pattern format defaults (compatible with vanilla Minecraft) + # Note: Can't use ${VAR:=default} syntax because } in the value breaks parsing + if [ -z "${LOG_CONSOLE_FORMAT}" ]; then + LOG_CONSOLE_FORMAT='[%d{HH:mm:ss}] [%t/%level]: %msg%n' + fi + if [ -z "${LOG_TERMINAL_FORMAT}" ]; then + LOG_TERMINAL_FORMAT='[%d{HH:mm:ss} %level]: %msg%n' + fi + if [ -z "${LOG_FILE_FORMAT}" ]; then + LOG_FILE_FORMAT='[%d{HH:mm:ss}] [%t/%level]: %msg%n' + fi + + export LOG_LEVEL ROLLING_LOG_FILE_PATTERN ROLLING_LOG_MAX_FILES + export LOG_CONSOLE_FORMAT LOG_TERMINAL_FORMAT LOG_FILE_FORMAT + + + # Always regenerate if file doesn't exist + if [ ! -e "$LOGFILE" ] || isTrue "${REGENERATE_LOG4J2:-true}"; then + log "Generating log4j2.xml from template in ${LOGFILE}" + + # Generate log4j2.xml using heredoc for reliable variable substitution + cat > "$LOGFILE" < + + + + + + + + + + + + + + + + + + + + + + + + + + + + +EOF + else + log "log4j2.xml already exists and is up to date, skipping generation" + fi + + # Apply the log4j2 configuration + JVM_OPTS="-Dlog4j.configurationFile=log4j2.xml ${JVM_OPTS}" +else + rm -f "${LOGFILE}" +fi