From 3fa40c285fec0e2a8318f017426ec325c11be9b8 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Fri, 13 Nov 2026 08:34:29 +0000
Subject: [PATCH] [#1289] Make temporary directory checks portable to ksh93 (#1291)
---
.github/scripts/test-script-util.sh | 95 +++++++++++++++++++++++++++++++
.github/workflows/build.yml | 8 ++
opendj-server-legacy/resource/bin/_script-util.sh | 23 +++----
3 files changed, 113 insertions(+), 13 deletions(-)
diff --git a/.github/scripts/test-script-util.sh b/.github/scripts/test-script-util.sh
new file mode 100644
index 0000000..e3cb97c
--- /dev/null
+++ b/.github/scripts/test-script-util.sh
@@ -0,0 +1,95 @@
+#!/bin/sh
+#
+# The contents of this file are subject to the terms of the Common Development and
+# Distribution License (the License). You may not use this file except in compliance with the
+# License.
+#
+# You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
+# specific language governing permission and limitations under the License.
+#
+# When distributing Covered Software, include this CDDL Header Notice in each file and include
+# the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
+# Header, with the fields enclosed by brackets [] replaced by your own identifying
+# information: "Portions copyright [year] [name of copyright owner]".
+#
+# Copyright 2026 3A Systems, LLC.
+
+set -eu
+root=$(CDPATH= cd -- "$(dirname "$0")/../.." && pwd)
+test_dir=$(mktemp -d "${TMPDIR:-/tmp}/opendj-script-util.XXXXXX")
+trap 'rm -rf "$test_dir"' 0
+
+INSTALL_ROOT=$test_dir
+INSTANCE_ROOT=$test_dir
+SCRIPT_UTIL_CMD=
+SCRIPT_NAME=setup
+. "$root/opendj-server-legacy/resource/bin/_script-util.sh"
+
+mkdir "$test_dir/tmp" "$test_dir/home"
+OPENDJ_TMP_DIR=$test_dir/tmp
+HOME=$test_dir/home
+OPENDJ_JAVA_ARGS=
+
+# On an executable filesystem, the real probe must succeed without shell errors
+# or leaking its scratch variables into the caller.
+res=caller
+DIR_TO_TEST=$test_dir/caller
+TMP_FILE=$test_dir/caller-file
+remove_dir=caller
+if ! set_bc_dir >"$test_dir/output" 2>&1; then
+ cat "$test_dir/output" >&2
+ exit 1
+fi
+if [ -s "$test_dir/output" ]; then
+ cat "$test_dir/output" >&2
+ exit 1
+fi
+test -z "$OPENDJ_JAVA_ARGS"
+test "$res:$DIR_TO_TEST:$TMP_FILE:$remove_dir" = "caller:$test_dir/caller:$test_dir/caller-file:caller"
+test -z "$(ls -A "$OPENDJ_TMP_DIR")"
+
+# Prevent the probe file in the temporary directory from becoming executable,
+# while allowing the real probe to make and execute its file in HOME.
+chmod() {
+ case $2 in
+ "$OPENDJ_TMP_DIR"/*) ;;
+ *) command chmod "$@" ;;
+ esac
+}
+set_bc_dir >"$test_dir/output" 2>&1
+unset -f chmod
+test "$OPENDJ_JAVA_ARGS" = " -Dorg.bouncycastle.native.loader.install_dir=$HOME"
+test -z "$(ls -A "$OPENDJ_TMP_DIR")"
+test -z "$(ls -A "$HOME")"
+OPENDJ_JAVA_ARGS=
+
+# A directory created by the real probe must be removed afterwards.
+check_noexec "$test_dir/missing"
+test ! -e "$test_dir/missing"
+
+# Simulate a noexec mount: the production selection logic still runs, while
+# the probe returns the result of attempting to execute from each directory.
+check_noexec() { [ "$1" = "$HOME" ]; }
+set_bc_dir >"$test_dir/output" 2>&1
+test "$OPENDJ_JAVA_ARGS" = " -Dorg.bouncycastle.native.loader.install_dir=$HOME"
+grep -F "WARNING: $OPENDJ_TMP_DIR is mounted as noexec" "$test_dir/output" >/dev/null
+if grep -F 'the OpenDJ installation could cause errors' "$test_dir/output" >/dev/null; then
+ cat "$test_dir/output" >&2
+ exit 1
+fi
+
+# An explicit BC installation directory must be preserved without probing.
+OPENDJ_JAVA_ARGS='-Dorg.bouncycastle.native.loader.install_dir=/chosen'
+check_noexec() { echo 'unexpected probe'; return 1; }
+set_bc_dir >"$test_dir/output" 2>&1
+test ! -s "$test_dir/output"
+test "$OPENDJ_JAVA_ARGS" = '-Dorg.bouncycastle.native.loader.install_dir=/chosen'
+
+# If neither directory permits execution, report it and do not set a fallback.
+OPENDJ_JAVA_ARGS=
+check_noexec() { return 1; }
+set_bc_dir >"$test_dir/output" 2>&1
+test -z "$OPENDJ_JAVA_ARGS"
+grep -F 'the OpenDJ installation could cause errors' "$test_dir/output" >/dev/null
+
+echo 'script-util checks passed'
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index e896efe..2e20694 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -62,6 +62,14 @@
if: runner.os == 'Linux' && matrix.java == '11'
shell: bash
run: bash .github/scripts/test-refresh-launchers.sh
+ - name: Check shell utility with ksh93
+ if: runner.os == 'macOS' && matrix.java == '11'
+ shell: bash
+ run: /bin/ksh .github/scripts/test-script-util.sh
+ - name: Check shell utility with dash
+ if: runner.os == 'Linux' && matrix.java == '11'
+ shell: bash
+ run: dash .github/scripts/test-script-util.sh
- name: Java ${{ matrix.Java }} (${{ matrix.os }})
uses: actions/setup-java@b843ebf9b913146b38da2eaa7aeddf76074ae1ad # v6.1.0
with:
diff --git a/opendj-server-legacy/resource/bin/_script-util.sh b/opendj-server-legacy/resource/bin/_script-util.sh
index 67324ab..6eaff75 100644
--- a/opendj-server-legacy/resource/bin/_script-util.sh
+++ b/opendj-server-legacy/resource/bin/_script-util.sh
@@ -83,17 +83,18 @@
export OPENDJ_JAVA_BIN
}
-check_noexec() { #returns 0 if can execute files in the directory, otherwise 1
- local DIR_TO_TEST=$1
- local res=0
- local remove_dir=0
+# Use a subshell to keep the probe's variables private in POSIX shells.
+check_noexec() ( #returns 0 if can execute files in the directory, otherwise 1
+ DIR_TO_TEST=$1
+ res=0
+ remove_dir=0
if [ ! -d "${DIR_TO_TEST}" ]; then
remove_dir=1
mkdir ${DIR_TO_TEST}
fi
- local TMP_FILE=`mktemp ${DIR_TO_TEST}/temp.XXXXXX`
+ TMP_FILE=`mktemp ${DIR_TO_TEST}/temp.XXXXXX`
chmod +x ${TMP_FILE}
if ! ${TMP_FILE} 2>/dev/null; then
@@ -107,23 +108,19 @@
fi
return $res
-}
+)
set_bc_dir() {
if echo "$OPENDJ_JAVA_ARGS" | grep -q -o "\-Dorg.bouncycastle.native.loader.install_dir=[^ ]*"; then
return # bc install dir already set
fi
- check_noexec "${OPENDJ_TMP_DIR}"
- local res=$?
- if [ $res = 1 ]; then
+ if ! check_noexec "${OPENDJ_TMP_DIR}"; then
if [ "$SCRIPT_NAME" = "setup" ]; then
echo "WARNING: $OPENDJ_TMP_DIR is mounted as noexec, try switching to $HOME for org.bouncycastle.native.loader.install_dir"
fi
- check_noexec "${HOME}"
- res=$?
- if [ $res = 0 ]; then
- OPENDJ_JAVA_ARGS="${OPENDJ_JAVA_ARGS} -Dorg.bouncycastle.native.loader.install_dir=${HOME}"
+ if check_noexec "${HOME}"; then
+ OPENDJ_JAVA_ARGS="${OPENDJ_JAVA_ARGS} -Dorg.bouncycastle.native.loader.install_dir=${HOME}"
elif [ "$SCRIPT_NAME" = "setup" ]; then
echo "WARNING: $HOME is mounted as noexec, the OpenDJ installation could cause errors"
fi
--
Gitblit v1.10.0