From 5f338723b6754a1273203d50c9ad62d116960a16 Mon Sep 17 00:00:00 2001
From: ghidra1
Date: Fri, 3 Jan 2025 13:19:43 -0500
Subject: [PATCH] GP-5161 Corrected Ghidra Server CME, document updates, and
launch script improvements to control Java home determination.
---
.../server/remote/RepositoryHandleImpl.java | 21 +-
.../Common/server/svrREADME.html | 69 ++++--
Ghidra/RuntimeScripts/Linux/server/ghidraSvr | 213 ++++++++++--------
Ghidra/RuntimeScripts/Linux/support/launch.sh | 92 ++++----
.../Windows/server/ghidraSvr.bat | 96 +++++---
.../RuntimeScripts/Windows/support/launch.bat | 62 +++--
.../src/main/java/LaunchSupport.java | 91 ++++++--
.../java/ghidra/launch/LaunchProperties.java | 15 +-
GhidraDocs/InstallationGuide.md | 34 +--
9 files changed, 444 insertions(+), 249 deletions(-)
diff --git a/Ghidra/Features/GhidraServer/src/main/java/ghidra/server/remote/RepositoryHandleImpl.java b/Ghidra/Features/GhidraServer/src/main/java/ghidra/server/remote/RepositoryHandleImpl.java
index 0bbbae1f1a..8a81debdab 100644
--- a/Ghidra/Features/GhidraServer/src/main/java/ghidra/server/remote/RepositoryHandleImpl.java
+++ b/Ghidra/Features/GhidraServer/src/main/java/ghidra/server/remote/RepositoryHandleImpl.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -21,8 +21,7 @@ import java.rmi.NoSuchObjectException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.server.Unreferenced;
-import java.util.HashMap;
-import java.util.LinkedList;
+import java.util.*;
import db.buffers.*;
import ghidra.framework.remote.*;
@@ -118,7 +117,9 @@ public class RepositoryHandleImpl extends UnicastRemoteObject
try {
repository.log(null, "Clearning " + transientCheckouts.size() + " transiet checkouts",
currentUser);
- for (String pathname : transientCheckouts.keySet()) {
+
+ ArrayList pathnames = new ArrayList<>(transientCheckouts.keySet());
+ for (String pathname : pathnames) {
int index = pathname.lastIndexOf(FileSystem.SEPARATOR_CHAR);
String parentPath = FileSystem.SEPARATOR;
if (index != 0) {
@@ -127,10 +128,12 @@ public class RepositoryHandleImpl extends UnicastRemoteObject
String itemName = pathname.substring(index + 1);
ItemCheckoutStatus transientCheckout = transientCheckouts.get(pathname);
-
- // Since dropped transient checkouts could occur in large volume due to headless
- // processing, don't bother sending notification
- terminateCheckout(parentPath, itemName, transientCheckout.getCheckoutId(), false);
+ if (transientCheckout != null) {
+ // Since dropped transient checkouts could occur in large volume due to headless
+ // processing, don't bother sending notification
+ terminateCheckout(parentPath, itemName, transientCheckout.getCheckoutId(),
+ false);
+ }
}
}
catch (IOException e) {
diff --git a/Ghidra/RuntimeScripts/Common/server/svrREADME.html b/Ghidra/RuntimeScripts/Common/server/svrREADME.html
index d7c6dd8487..e8a2e0e19b 100644
--- a/Ghidra/RuntimeScripts/Common/server/svrREADME.html
+++ b/Ghidra/RuntimeScripts/Common/server/svrREADME.html
@@ -60,6 +60,7 @@ typewriter {
-
-
-NOTE: It is highly recommended that you establish a repositories directory outside of your
-Ghidra installation directory so that it may be re-used more easily with future upgraded
-installations of Ghidra.
-
+
You may also refer to the InstallationGuide.html file within the
@@ -137,8 +132,20 @@ location and other associated options.
-You should generally avoid using the default repositories location and specify a location outside
-your installation directory using an absolute path specification.
+It is highly recommended that you specify a repositories directory outside of your
+Ghidra installation directory with an absolute path so that it may be re-used more easily with
+future upgraded installations of Ghidra. Due to the use of a filesystem
+watcher service the use of a locally attached storage device is preferred and will also ensure
+the best performance.
+
+
+
+NOTE: The server may fail to start if the repository native filesystem does
+not support the use of a filesystem watcher service. This could occur if attempting to use a
+remotely-mounted filesystem which may lack the required event support. The watcher service is used
+in conjunction with command processing associated with the svrAdmin command. If a running
+server fails to process queued svrAdmin command requests, the repository native filesystem
+may be the cause.
@@ -401,7 +408,7 @@ are not currently supported.
-autoProvision
Enable the auto-creation of new Ghidra Server
users when they successfully authenticate to the server (-a1 and -a4 modes only).
Users removed from the authentication provider (e.g., Active Directory) will need to be
- deleted manually from the Ghidra Server using svrAdmin command.
+ deleted manually from the Ghidra Server using svrAdmin command.
-anonymous
Enable anonymous access support for Ghidra Server
and its repositories. Only those repositories which specifically enable anonymous access will be
@@ -555,8 +562,26 @@ are not currently supported.
The Ghidra Server may be installed as an automatic service by executing the
svrInstall script. Once installed, the server will start automatically
- when the system is booted.
+ when the system is booted. If performing an upgrade to an existing Ghidra Server installation
+ you must uninstall the existing Ghidra Server first (see
+ Uninstall Service).
+
+ In order for the installed service script to survive Java system updates, which may change
+ the installed Java version, it is highly recommended that the GHIDRA_JAVA_HOME variable be set
+ properly at the top of the ghidraSvr script prior to the server install.
+ GHIDRA_JAVA_HOME should refer to a non-changing path where Java is installed. For a system-installed
+ Java the major-version symblic-link path should be specified in favor of a
+ full-version path which stipulates minor-version information. In addition, it is important
+ that the Ghidra Server service be restarted anytime the installed Java version is updated where
+ this symbolic link has been modified to reference a newly installed Java version. Failure to
+ use this approach may result in the Ghidra Server service script referring to an invalid Java
+ path following an update.
+
+Example setting of GHIDRA_JAVA_HOME within ghidraSvr script:
+
+ GHIDRA_JAVA_HOME=/usr/lib/jvm/java-21-openjdk
+
If it is preferred to run the service with a dedicated local user account, the following
entry may be added to the server.conf file with the appropriate account specified in
@@ -567,7 +592,7 @@ are not currently supported.
installation of the Ghidra Server service.
- wrapper.app.account=<uid>
+ wrapper.app.account=<uid>
It is also important that the repositories directory and Ghidra installation files
@@ -582,14 +607,20 @@ to run as root and monitor/manage the Java process.
svrUninstall script.
- NOTE: It is very important that you uninstall the service prior to doing any of the following
- activities:
-
+ IMPORTANT: It is very important that you uninstall the Ghidra Server service using the
+ original Ghidra software installation. Use of a newer Ghidra software install may not properly
+ uninstall a different service version. This is particularly true if uninstalling
+ a Ghidra Server version prior to 11.2. Such an uninstall will be required when:
- deleting or upgrading the Ghidra installation
- moving/renaming the Ghidra installation directory
+
+ NOTE: The service control mechanism for Linux changed with the Ghidra 11.2 release.
+ The init.d mechanism was previously used in all cases, whereas the
+ systemd service mechanism may now used based upon YAJSW preference.
+
(Back to Top)
@@ -1007,6 +1038,14 @@ newer SSL/TLS enabled Ghidra Server registry, the following connection error wil
non-JRMP server at remote endpoint
+
+
+
+MS Windows - ERROR Incorrect function (WindowsWatchService)
+
+The Ghidra Server employs a file system watcher service for the repositories directory which must
+reside within a locally mounted NTFS or ReFS filesystem.
+
MS Windows - ERROR Missing Temp Directory
diff --git a/Ghidra/RuntimeScripts/Linux/server/ghidraSvr b/Ghidra/RuntimeScripts/Linux/server/ghidraSvr
index 29831c671e..bb171c202d 100755
--- a/Ghidra/RuntimeScripts/Linux/server/ghidraSvr
+++ b/Ghidra/RuntimeScripts/Linux/server/ghidraSvr
@@ -5,13 +5,24 @@
# Usage: ghidraSvr [ console | status | install | uninstall | start | stop | restart ]
#---------------------------------------------------------------------------------------
-# The Java 21 (or later) runtime installation must either be on the system path or identified
-# by setting the JAVA_HOME environment variable. If not using a formally installed Java
-# runtime which has been configured into the system PATH ahead of other Java installations
-# it may be necessary to explicitly specify the path to the installation by setting JAVA_HOME
-# below:
+# The Java 21 (or later) runtime installation must either be on the system path, specified by the
+# JAVA_HOME environment variable or preferably set explicitly with the GHIDRA_JAVA_HOME variable
+# below. Since this script may be used during service initialization, reliance on environmental
+# settings such as JAVA_HOME may be problematic. It is also important to note that once installed
+# as a service, changes to this file or environmental settings may not have an affect on any service
+# scripts that was generated at the time of service installation.
+#
+# When specifying GHIDRA_JAVA_HOME below it is recommended that a symbolic link path be specified
+# which only includes the major java version so that any system Java updates will allow for this
+# path to remain valid. In the case of Linux, this is important since once the Ghidra Server is
+# installed as a systemd service the Java path will be locked-in to the generated ghidra.service
+# script.
+#
+# Example: The symbolic link "/usr/lib/jvm/java-21-openjdk" should be specified in favor of a
+# version-specific path such as "/usr/lib/jvm/java-21-openjdk-21.0.5.0.10-3.el8.x86_64".
-# JAVA_HOME=
+# Uncomment the following line and set JAVA_HOME before installing as a service
+# GHIDRA_JAVA_HOME=/usr/lib/jvm/java-21-openjdk
OPTION=$1
@@ -25,29 +36,30 @@ usage() {
adminFail() {
echo
- echo "Command option \"$OPTION\" must be run as administrator (use elevated shell - see svrREADME.html)"
+ echo "Command option \"${OPTION}\" must be run as administrator (use elevated shell - see svrREADME.html)"
echo
exit 1
}
reportError() {
echo
- echo "$1"
+ echo -e "ERROR: $1"
+ echo "Please refer to the svrREADME documentation."
echo
- echo "$1" >> "${GHIDRA_HOME}/wrapper.log"
+ echo -e "ERROR: $1" >> "${GHIDRA_HOME}/wrapper.log"
exit 1
}
-if [ "$OPTION" == "" ]; then
+if [ "${OPTION}" == "" ]; then
usage
fi
-if [ "$EUID" != "0" ]; then
- if [ "$OPTION" == "start" ]; then adminFail
- elif [ "$OPTION" == "stop" ]; then adminFail
- elif [ "$OPTION" == "install" ]; then adminFail
- elif [ "$OPTION" == "uninstall" ]; then adminFail
- elif [ "$OPTION" == "restart" ]; then adminFail
+if [ "${EUID}" != "0" ]; then
+ if [ "${OPTION}" == "start" ]; then adminFail
+ elif [ "${OPTION}" == "stop" ]; then adminFail
+ elif [ "${OPTION}" == "install" ]; then adminFail
+ elif [ "${OPTION}" == "uninstall" ]; then adminFail
+ elif [ "${OPTION}" == "restart" ]; then adminFail
fi
fi
@@ -55,7 +67,7 @@ APP_NAME="ghidraSvr"
APP_LONG_NAME="Ghidra Server"
MODULE_DIR="Ghidra/Features/GhidraServer"
WRAPPER_NAME_PREFIX=yajsw
-SERVICE_NAME=org.rzo.yajsw.$APP_NAME
+SERVICE_NAME=org.rzo.yajsw.${APP_NAME}
WRAPPER_TMPDIR="${TMPDIR:-/tmp}"
# Resolve symbolic link if present and get the directory this script lives in.
@@ -66,7 +78,7 @@ SCRIPT_FILE="$(readlink -f "$0" 2>/dev/null || readlink "$0" 2>/dev/null || echo
SCRIPT_DIR="${SCRIPT_FILE%/*}"
# Ensure Ghidra path doesn't contain illegal characters
-if [[ "$SCRIPT_DIR" = *"!"* ]]; then
+if [[ "${SCRIPT_DIR}" = *"!"* ]]; then
echo "Ghidra path cannot contain a \"!\" character."
exit 1
fi
@@ -76,7 +88,7 @@ cd "${SCRIPT_DIR}"
SCRIPT_DIR="$(pwd)"
OS="$(uname -s)"
-if [ "$OS" = "Darwin" ]; then
+if [ "${OS}" = "Darwin" ]; then
OS_DIRNAME="osx64"
else
OS_DIRNAME="linux64"
@@ -117,33 +129,48 @@ if [ ! -d "${WRAPPER_HOME}" -o ! -f "${WRAPPER_HOME}/wrapper.jar" ]; then
exit 1
fi
-echo "Using service wrapper: $(basename "$WRAPPER_HOME")"
+echo "Using service wrapper: $(basename "${WRAPPER_HOME}")"
# Determine the Java command to use to start the JVM.
-JAVA_CMD=java
-if [ -n "$JAVA_HOME" ] ; then
- if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
- # IBM's JDK on AIX uses strange locations for the executables
- JAVA_CMD="$JAVA_HOME/jre/sh/java"
- else
- JAVA_CMD="$JAVA_HOME/bin/java"
- fi
- if [ ! -x "$JAVA_CMD" ] ; then
- reportError "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME"
+JAVA_CMD=
+if [ -n "${GHIDRA_JAVA_HOME}" ] ; then
+ # Identify java command from GHIDRA_JAVA_HOME
+ JAVA_CMD="${GHIDRA_JAVA_HOME}/bin/java"
+ if [ ! -x "${JAVA_CMD}" ] ; then
+ reportError "The ghidraSvr script GHIDRA_JAVA_HOME variable is set to an invalid directory: ${GHIDRA_JAVA_HOME}"
+ fi
+
+ $("${JAVA_CMD}" -cp "${LS_CPATH}" LaunchSupport "${GHIDRA_HOME}" -java_home_check "${GHIDRA_JAVA_HOME}")
+ if [ ! $? -eq 0 ] ; then
+ reportError "The ghidraSvr script GHIDRA_JAVA_HOME variable specifies an invalid or unsupported Java runtime: ${GHIDRA_JAVA_HOME}"
fi
else
- JAVA_CMD="java"
- which java >/dev/null 2>&1 || reportError "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH."
-fi
+ # Identify java command from either JAVA_HOME or PATH, try PATH first
+ JAVA_CMD=
+ if [ -x "$(command -v java)" ] ; then
+ JAVA_CMD=java
+ elif [ -n "${JAVA_HOME}" ] ; then
+ JAVA_CMD="${JAVA_HOME}/bin/java"
+ if [ ! -x "${JAVA_CMD}" ] ; then
+ echo "WARNING: JAVA_HOME environment variable is set to an invalid directory: ${JAVA_HOME}"
+ JAVA_CMD=
+ fi
+ fi
+
+ if [ "${JAVA_CMD}" == "" ]; then
+ reportError "The 'java' command could not be found in your PATH or with JAVA_HOME."
+ fi
+
+ # Get the java that will be used to launch GhidraServer
+ # Ensure that locally-set JAVA_HOME environment variable passes thru to LaunchSupport
+ LS_JAVA_HOME=$("${JAVA_CMD}" -cp "${LS_CPATH}" LaunchSupport "${GHIDRA_HOME}" -java_home)
+ if [ ! $? -eq 0 ] ; then
+ reportError "Unable to find a supported Java runtime on your system."
+ fi
-# Get the java that will be used to launch GhidraServer
-JAVA_HOME=$($JAVA_CMD -cp "${LS_CPATH}" LaunchSupport "${GHIDRA_HOME}" -java_home)
-if [ ! $? -eq 0 ]; then
- reportError "Failed to find a supported Java runtime. Please refer to the Ghidra Installation Guide's Troubleshooting section."
+ JAVA_CMD="${LS_JAVA_HOME}/bin/java"
fi
-JAVA_CMD="${JAVA_HOME}/bin/java"
-
VMARGS=()
VMARGS+=("-Djna_tmpdir=${WRAPPER_TMPDIR}")
VMARGS+=("-Djava.io.tmpdir=${WRAPPER_TMPDIR}")
@@ -151,14 +178,14 @@ VMARGS+=("-Djava.io.tmpdir=${WRAPPER_TMPDIR}")
enableForkHack() {
# use of fork_hack only needed for Mac OS X
- if [ "$OS" != "Darwin" ]; then
+ if [ "${OS}" != "Darwin" ]; then
return 0
fi
# watch out for revisions to the associated fork_hack comment in server.conf
# that could throw this off
HAS_FORK_HACK_LINE="$(grep "wrapper.fork_hack=" "${WRAPPER_CONF}")"
- HAS_FORK_HACK_LINE=$(echo $HAS_FORK_HACK_LINE)
+ HAS_FORK_HACK_LINE=$(echo ${HAS_FORK_HACK_LINE})
if [ "${HAS_FORK_HACK_LINE}" = "wrapper.fork_hack=true" ]; then
return 0
fi
@@ -200,81 +227,81 @@ checkInstall() {
}
console() {
- echo "Running ${APP_LONG_NAME}..."
- java="${JAVA_CMD}" ghidra_home="${GHIDRA_HOME}" classpath_frag="${CLASSPATH_FRAG}" wrapper_tmpdir="${WRAPPER_TMPDIR}" "${JAVA_CMD}" "${VMARGS[@]}" -jar "${WRAPPER_HOME}/wrapper.jar" -c "${WRAPPER_CONF}"
+ echo "Running ${APP_LONG_NAME}..."
+ java="${JAVA_CMD}" ghidra_home="${GHIDRA_HOME}" classpath_frag="${CLASSPATH_FRAG}" wrapper_tmpdir="${WRAPPER_TMPDIR}" "${JAVA_CMD}" "${VMARGS[@]}" -jar "${WRAPPER_HOME}/wrapper.jar" -c "${WRAPPER_CONF}"
}
start() {
- echo "Starting ${APP_LONG_NAME}..."
- java="${JAVA_CMD}" ghidra_home="${GHIDRA_HOME}" classpath_frag="${CLASSPATH_FRAG}" wrapper_tmpdir="${WRAPPER_TMPDIR}" "${JAVA_CMD}" "${VMARGS[@]}" -jar "${WRAPPER_HOME}/wrapper.jar" -t "${WRAPPER_CONF}"
+ echo "Starting ${APP_LONG_NAME}..."
+ java="${JAVA_CMD}" ghidra_home="${GHIDRA_HOME}" classpath_frag="${CLASSPATH_FRAG}" wrapper_tmpdir="${WRAPPER_TMPDIR}" "${JAVA_CMD}" "${VMARGS[@]}" -jar "${WRAPPER_HOME}/wrapper.jar" -t "${WRAPPER_CONF}"
}
stopit() {
- echo "Stopping ${APP_LONG_NAME}..."
- java="${JAVA_CMD}" ghidra_home="${GHIDRA_HOME}" classpath_frag="${CLASSPATH_FRAG}" wrapper_tmpdir="${WRAPPER_TMPDIR}" "${JAVA_CMD}" "${VMARGS[@]}" -jar "${WRAPPER_HOME}/wrapper.jar" -p "${WRAPPER_CONF}"
+ echo "Stopping ${APP_LONG_NAME}..."
+ java="${JAVA_CMD}" ghidra_home="${GHIDRA_HOME}" classpath_frag="${CLASSPATH_FRAG}" wrapper_tmpdir="${WRAPPER_TMPDIR}" "${JAVA_CMD}" "${VMARGS[@]}" -jar "${WRAPPER_HOME}/wrapper.jar" -p "${WRAPPER_CONF}"
}
install() {
- echo "Installing ${APP_LONG_NAME}..."
- java="${JAVA_CMD}" ghidra_home="${GHIDRA_HOME}" classpath_frag="${CLASSPATH_FRAG}" wrapper_tmpdir="${WRAPPER_TMPDIR}" "${JAVA_CMD}" "${VMARGS[@]}" -jar "${WRAPPER_HOME}/wrapper.jar" -i "${WRAPPER_CONF}"
+ echo "Installing ${APP_LONG_NAME}..."
+ java="${JAVA_CMD}" ghidra_home="${GHIDRA_HOME}" classpath_frag="${CLASSPATH_FRAG}" wrapper_tmpdir="${WRAPPER_TMPDIR}" "${JAVA_CMD}" "${VMARGS[@]}" -jar "${WRAPPER_HOME}/wrapper.jar" -i "${WRAPPER_CONF}"
}
uninstall() {
- echo "Uninstalling ${APP_LONG_NAME}..."
- java="${JAVA_CMD}" ghidra_home="${GHIDRA_HOME}" classpath_frag="${CLASSPATH_FRAG}" wrapper_tmpdir="${WRAPPER_TMPDIR}" "${JAVA_CMD}" "${VMARGS[@]}" -jar "${WRAPPER_HOME}/wrapper.jar" -r "${WRAPPER_CONF}"
+ echo "Uninstalling ${APP_LONG_NAME}..."
+ java="${JAVA_CMD}" ghidra_home="${GHIDRA_HOME}" classpath_frag="${CLASSPATH_FRAG}" wrapper_tmpdir="${WRAPPER_TMPDIR}" "${JAVA_CMD}" "${VMARGS[@]}" -jar "${WRAPPER_HOME}/wrapper.jar" -r "${WRAPPER_CONF}"
}
status() {
- java="${JAVA_CMD}" ghidra_home="${GHIDRA_HOME}" classpath_frag="${CLASSPATH_FRAG}" wrapper_tmpdir="${WRAPPER_TMPDIR}" "${JAVA_CMD}" "${VMARGS[@]}" -jar "${WRAPPER_HOME}/wrapper.jar" -q "${WRAPPER_CONF}"
+ java="${JAVA_CMD}" ghidra_home="${GHIDRA_HOME}" classpath_frag="${CLASSPATH_FRAG}" wrapper_tmpdir="${WRAPPER_TMPDIR}" "${JAVA_CMD}" "${VMARGS[@]}" -jar "${WRAPPER_HOME}/wrapper.jar" -q "${WRAPPER_CONF}"
}
case "$1" in
- 'console')
- enableForkHack
- console
- ;;
-
- 'status')
- status
- ;;
+ 'console')
+ enableForkHack
+ console
+ ;;
+
+ 'status')
+ status
+ ;;
- 'start')
- checkInstall
- if [ $? = 0 ]; then
- start
- fi
- ;;
+ 'start')
+ checkInstall
+ if [ $? = 0 ]; then
+ start
+ fi
+ ;;
- 'stop')
- checkInstall
- if [ $? = 0 ]; then
- stopit
- fi
- ;;
+ 'stop')
+ checkInstall
+ if [ $? = 0 ]; then
+ stopit
+ fi
+ ;;
- 'restart')
- checkInstall
- if [ $? = 0 ]; then
- stopit
- start
- fi
- ;;
+ 'restart')
+ checkInstall
+ if [ $? = 0 ]; then
+ stopit
+ start
+ fi
+ ;;
- 'install')
- enableForkHack
- install
- start
- ;;
+ 'install')
+ enableForkHack
+ install
+ start
+ ;;
- 'uninstall')
- checkInstall
- if [ $? = 0 ]; then
- uninstall
- fi
- ;;
+ 'uninstall')
+ checkInstall
+ if [ $? = 0 ]; then
+ uninstall
+ fi
+ ;;
- *)
- usage
- ;;
+ *)
+ usage
+ ;;
esac
diff --git a/Ghidra/RuntimeScripts/Linux/support/launch.sh b/Ghidra/RuntimeScripts/Linux/support/launch.sh
index 0b8b0874d7..f7a130628d 100755
--- a/Ghidra/RuntimeScripts/Linux/support/launch.sh
+++ b/Ghidra/RuntimeScripts/Linux/support/launch.sh
@@ -1,18 +1,18 @@
#!/usr/bin/env bash
## ###
-# IP: GHIDRA
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
+# IP: GHIDRA
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
##
umask 027
@@ -21,31 +21,30 @@ function showUsage() {
echo "Usage: $0 \"\" ... "
echo " : fg run as foreground process in current shell"
- echo " bg run as background process in new shell"
- echo " debug run as foreground process in current shell in debug mode (suspend=n)"
- echo " debug-suspend run as foreground process in current shell in debug mode (suspend=y)"
- echo " NOTE: for all debug modes environment variable DEBUG_ADDRESS may be set to "
- echo " override default debug address of 127.0.0.1:18001"
+ echo " bg run as background process in new shell"
+ echo " debug run as foreground process in current shell in debug mode (suspend=n)"
+ echo " debug-suspend run as foreground process in current shell in debug mode (suspend=y)"
+ echo " NOTE: for all debug modes environment variable DEBUG_ADDRESS may be set to "
+ echo " override default debug address of 127.0.0.1:18001"
echo " : jdk requires JDK to run"
- echo " jre JRE is sufficient to run (JDK works too)"
+ echo " jre JRE is sufficient to run (JDK works too)"
echo " : application name used for naming console window"
echo " : maximum memory heap size in MB (e.g., 768M or 2G). Use empty \"\" if default"
- echo " should be used. This will generally be upto 1/4 of the physical memory available"
- echo " to the OS."
+ echo " should be used. This will generally be upto 1/4 of the physical memory available"
+ echo " to the OS."
echo " : pass-thru args (e.g., \"-Xmx512M -Dmyvar=1 -DanotherVar=2\"). Use"
- echo " empty \"\" if vmargs not needed. Spaces are not supported."
+ echo " empty \"\" if vmargs not needed. Spaces are not supported."
echo " : application classname (e.g., ghidra.GhidraRun )"
echo " ...: arguments to be passed to the application"
echo " "
echo " Example:"
- echo " \"$0\" debug jdk Ghidra 4G \"\" ghidra.GhidraRun"
+ echo " \"$0\" debug jdk Ghidra 4G \"\" ghidra.GhidraRun"
exit 1
}
-
-VMARGS_FROM_CALLER= # Passed in from the outer script as one long string, no spaces
-VMARGS_FROM_LAUNCH_SH=() # Defined in this script, added to array
+VMARGS_FROM_CALLER= # Passed in from the outer script as one long string, no spaces
+VMARGS_FROM_LAUNCH_SH=() # Defined in this script, added to array
VMARGS_FROM_LAUNCH_PROPS=() # Retrieved from LaunchSupport, added to array
ARGS=()
@@ -97,7 +96,7 @@ fi
SUPPORT_DIR="${0%/*}"
# Ensure Ghidra path doesn't contain illegal characters
-if [[ "$SUPPORT_DIR" = *"!"* ]]; then
+if [[ "${SUPPORT_DIR}" = *"!"* ]]; then
echo "Ghidra path cannot contain a \"!\" character."
exit 1
fi
@@ -119,46 +118,61 @@ else
CPATH="${INSTALL_DIR}/Ghidra/Framework/Utility/build/libs/Utility.jar"
LS_CPATH="${INSTALL_DIR}/GhidraBuild/LaunchSupport/build/libs/LaunchSupport.jar"
if ! [ -f "${LS_CPATH}" ]; then
- echo "Cannot launch from repo because Ghidra has not been compiled with Eclipse or Gradle."
+ echo "ERROR: Cannot launch from repo because Ghidra has not been compiled with Eclipse or Gradle."
exit 1
fi
fi
DEBUG_LOG4J="${INSTALL_DIR}/Ghidra/RuntimeScripts/Common/support/debug.log4j.xml"
fi
-# Make sure some kind of java is on the path. It's required to run the LaunchSupport program.
-if ! [ -x "$(command -v java)" ] ; then
- echo "Java runtime not found. Please refer to the Ghidra Installation Guide's Troubleshooting section."
+# Identify java command from either JAVA_HOME or PATH, try PATH first
+JAVA_CMD=
+if [ -x "$(command -v java)" ] ; then
+ JAVA_CMD=java
+elif [ -n "${JAVA_HOME}" ] ; then
+ JAVA_CMD="${JAVA_HOME}/bin/java"
+ if [ ! -x "${JAVA_CMD}" ] ; then
+ echo "WARNING: JAVA_HOME environment variable is set to an invalid directory: ${JAVA_HOME}"
+ JAVA_CMD=
+ fi
+fi
+
+if [ "${JAVA_CMD}" == "" ]; then
+ echo
+ echo "ERROR: The 'java' command could not be found in your PATH or with JAVA_HOME."
+ echo "Please refer to the Ghidra Installation Guide's Troubleshooting section."
exit 1
fi
# Get the JDK that will be used to launch Ghidra
-JAVA_HOME="$(java -cp "${LS_CPATH}" LaunchSupport "${INSTALL_DIR}" ${JAVA_TYPE_ARG} -save)"
+LS_JAVA_HOME="$("${JAVA_CMD}" -cp "${LS_CPATH}" LaunchSupport "${INSTALL_DIR}" ${JAVA_TYPE_ARG} -save)"
if [ ! $? -eq 0 ]; then
# If fd 0 (stdin) isn't a tty, fail because we can't prompt the user
if [ ! -t 0 ]; then
echo
- echo "Unable to prompt user for JDK path, no TTY detected. Please refer to the Ghidra Installation Guide's Troubleshooting section."
+ echo "ERROR: Unable to prompt user for JDK path, no TTY detected."
+ echo "Please refer to the Ghidra Installation Guide's Troubleshooting section."
exit 1
fi
# No JDK has been setup yet. Let the user choose one.
- java -cp "${LS_CPATH}" LaunchSupport "${INSTALL_DIR}" ${JAVA_TYPE_ARG} -ask
+ "${JAVA_CMD}" -cp "${LS_CPATH}" LaunchSupport "${INSTALL_DIR}" ${JAVA_TYPE_ARG} -ask
# Now that the user chose one, try again to get the JDK that will be used to launch Ghidra
- JAVA_HOME="$(java -cp "${LS_CPATH}" LaunchSupport "${INSTALL_DIR}" ${JAVA_TYPE_ARG} -save)"
+ LS_JAVA_HOME="$("${JAVA_CMD}" -cp "${LS_CPATH}" LaunchSupport "${INSTALL_DIR}" ${JAVA_TYPE_ARG} -save)"
if [ ! $? -eq 0 ]; then
echo
- echo "Failed to find a supported JDK. Please refer to the Ghidra Installation Guide's Troubleshooting section."
+ echo "ERROR: Failed to find a supported JDK."
+ echo "Please refer to the Ghidra Installation Guide's Troubleshooting section."
exit 1
fi
fi
-JAVA_CMD="${JAVA_HOME}/bin/java"
+JAVA_CMD="${LS_JAVA_HOME}/bin/java"
# Get the configurable VM arguments from the launch properties
while IFS=$'\r\n' read -r line; do
VMARGS_FROM_LAUNCH_PROPS+=("$line")
-done < <(java -cp "${LS_CPATH}" LaunchSupport "${INSTALL_DIR}" -vmargs)
+done < <("${JAVA_CMD}" -cp "${LS_CPATH}" LaunchSupport "${INSTALL_DIR}" -vmargs)
# Add extra macOS VM arguments
if [ "$(uname -s)" = "Darwin" ]; then
@@ -194,7 +208,7 @@ elif [ "${MODE}" = "bg" ]; then
BACKGROUND=true
else
- echo "Incorrect launch usage - invalid launch mode: ${MODE}"
+ echo "ERROR: Incorrect launch usage - invalid launch mode: ${MODE}"
exit 1
fi
diff --git a/Ghidra/RuntimeScripts/Windows/server/ghidraSvr.bat b/Ghidra/RuntimeScripts/Windows/server/ghidraSvr.bat
index 4d3795e1fb..41e2467e8e 100644
--- a/Ghidra/RuntimeScripts/Windows/server/ghidraSvr.bat
+++ b/Ghidra/RuntimeScripts/Windows/server/ghidraSvr.bat
@@ -1,17 +1,18 @@
@echo off
-rem ---------------------------------------------------------------------------------------
-rem Ghidra Server Script (see svrREADME.html for usage details)
-rem Usage: ghidraSvr [ console | status | install | uninstall | start | stop | restart ]
-rem ---------------------------------------------------------------------------------------
+:: ---------------------------------------------------------------------------------------
+:: Ghidra Server Script (see svrREADME.html for usage details)
+:: Usage: ghidraSvr [ console | status | install | uninstall | start | stop | restart ]
+:: ---------------------------------------------------------------------------------------
-rem The Java 21 (or later) runtime installation must either be on the system path or identified
-rem by setting the JAVA_HOME environment variable. If not using a formally installed Java
-rem runtime which has been configured into the system PATH ahead of other Java installations
-rem it may be necessary to explicitly specify the path to the installation by setting JAVA_HOME
-rem below:
+:: The Java 21 (or later) runtime installation must either be on the system path, specified by the
+:: JAVA_HOME environment variable or preferably set explicitly with the GHIDRA_JAVA_HOME variable
+:: below. Since this script may be used during service initialization, reliance on environmental
+:: settings such as JAVA_HOME may be problematic. It is also important to note that once installed
+:: as a service, changes to this file or environmental settings may not have an affect on any service
+:: registration that was generated at the time of service installation.
-rem set "JAVA_HOME="
+:: set "GHIDRA_JAVA_HOME="
:: Sets SERVER_DIR to the directory that contains this file (ghidraSvr.bat).
:: SERVER_DIR will not contain a trailing slash.
@@ -23,7 +24,7 @@ rem set "JAVA_HOME="
set "SERVER_DIR=%~dp0"
set "SERVER_DIR=%SERVER_DIR:~0,-1%"
-rem Ensure Ghidra path doesn't contain illegal characters
+:: Ensure Ghidra path doesn't contain illegal characters
if not "%SERVER_DIR:!=%"=="%SERVER_DIR%" (
echo Ghidra path cannot contain a "!" character.
exit /B 1
@@ -56,7 +57,7 @@ set IS_ADMIN=NO
whoami /groups | findstr "S-1-16-12288 " >NUL && set IS_ADMIN=YES
if "%IS_ADMIN%"=="NO" (
- rem The following command options require admin
+ :: The following command options require admin
if "%OPTION%"=="start" goto adminFail
if "%OPTION%"=="stop" goto adminFail
if "%OPTION%"=="install" goto adminFail
@@ -72,11 +73,11 @@ set "WRAPPER_TMPDIR=%TEMP%"
if exist "%SERVER_DIR%\..\Ghidra\" goto normal
-rem NOTE: If adjusting JAVA command assignment - do not attempt to add parameters (e.g., -d64, -version:1.7, etc.)
+:: NOTE: If adjusting JAVA command assignment - do not attempt to add parameters (e.g., -d64, -version:1.7, etc.)
-rem NOTE: Variables that get accessed in server.conf must be lowercase
+:: NOTE: Variables that get accessed in server.conf must be lowercase
-rem Development Environment (Eclipse classes or "gradle jar")
+:: Development Environment (Eclipse classes or "gradle jar")
set "GHIDRA_HOME=%SERVER_DIR%\..\..\..\.."
set "WRAPPER_CONF=%SERVER_DIR%\..\..\Common\server\server.conf"
set "DATA_DIR=%GHIDRA_HOME%\%MODULE_DIR%\build\data"
@@ -86,7 +87,7 @@ if not exist "%LS_CPATH%" (
set "LS_CPATH=%GHIDRA_HOME%\GhidraBuild\LaunchSupport\build\libs\LaunchSupport.jar"
)
if not exist "%LS_CPATH%" (
- set ERROR=ERROR: Cannot launch from repo because Ghidra has not been compiled with Eclipse or Gradle.
+ set ERROR=Cannot launch from repo because Ghidra has not been compiled with Eclipse or Gradle.
goto reportError
)
@@ -101,7 +102,7 @@ set "LS_CPATH=%GHIDRA_HOME%\support\LaunchSupport.jar"
:lab1
-rem set WRAPPER_HOME to unpacked yajsw location (crazy FOR syntax to set variable from command output)
+:: set WRAPPER_HOME to unpacked yajsw location (crazy FOR syntax to set variable from command output)
for /F "usebackq delims=" %%p in (`dir "%DATA_DIR%" /ad /b ^| findstr "^%WRAPPER_NAME_PREFIX%"`) do set WRAPPER_DIRNAME=%%p
set "WRAPPER_HOME=%DATA_DIR%\%WRAPPER_DIRNAME%"
@@ -114,34 +115,60 @@ if not exist "%WRAPPER_HOME%\" (
echo Using service wrapper: %WRAPPER_DIRNAME%
-rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
+:: Check for use of GHIDRA_JAVA_HOME
+if not defined GHIDRA_JAVA_HOME goto findJava
+set "java=%GHIDRA_JAVA_HOME%\bin\java.exe"
+"%java%" -version >NUL 2>&1
+if %ERRORLEVEL% neq 0 (
+ set ERROR=The ghidraSvr.bat script GHIDRA_JAVA_HOME variable is set to an invalid directory: %GHIDRA_JAVA_HOME%
+ goto reportError
+)
+
+:: Check specified GHIDRA_JAVA_HOME
+"%java%" -cp "%LS_CPATH%" LaunchSupport "%GHIDRA_HOME%" -java_home_check "%GHIDRA_JAVA_HOME%"
+if %ERRORLEVEL% neq 0 (
+ set ERROR=The ghidraSvr script GHIDRA_JAVA_HOME variable specifies an invalid or unsupported Java runtime: %GHIDRA_JAVA_HOME%
+ goto reportError
+)
+
+:: Bypass LaunchSupport java search when GHIDRA_JAVA_HOME is specified
+goto lab3
+
+:findJava
+
+:: check for java based upon PATH
set java=java.exe
-%java% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto lab2
-set ERROR=ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-goto reportError
+java.exe -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto lab2
-:findJavaFromJavaHome
+:: check for java based upon JAVA_HOME environment variable
+if not defined JAVA_HOME goto javaNotFound
set "java=%JAVA_HOME%\bin\java.exe"
+"%java%" -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto lab2
+echo WARNING: JAVA_HOME environment variable is set to an invalid directory: %JAVA_HOME%
-if exist "%java%" goto lab2
-set ERROR=ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+:javaNotFound
+set ERROR=The ghidraSvr.bat script GHIDRA_JAVA_HOME variable is not set and 'java' command could not be found in your PATH or with JAVA_HOME.
goto reportError
+:: Use LaunchSupport to locate supported java runtime
:lab2
:: Get the java that will be used to launch GhidraServer
-set JAVA_HOME=
-for /f "delims=*" %%i in ('call "%java%" -cp "%LS_CPATH%" LaunchSupport "%GHIDRA_HOME%" -java_home') do set JAVA_HOME=%%i
-if "%JAVA_HOME%" == "" (
- set ERROR=Failed to find a supported Java runtime. Please refer to the Ghidra Installation Guide's Troubleshooting section.
+set LS_JAVA_HOME=
+for /f "delims=*" %%i in ('call "%java%" -cp "%LS_CPATH%" LaunchSupport "%GHIDRA_HOME%" -java_home') do set LS_JAVA_HOME=%%i
+if "%LS_JAVA_HOME%" == "" (
+ set ERROR=Unable to find a supported Java runtime on your system.
goto reportError
)
-rem reestablish JAVA path based upon final JAVA_HOME
-set "java=%JAVA_HOME%\bin\java.exe"
+:: reestablish JAVA path based upon LS_JAVA_HOME
+set "java=%LS_JAVA_HOME%\bin\java.exe"
+
+:: execute command OPTION
+:lab3
set VMARGS=-Djava.io.tmpdir="%WRAPPER_TMPDIR%"
set VMARGS=%VMARGS% -Djna_tmpdir="%WRAPPER_TMPDIR%"
@@ -186,9 +213,10 @@ goto eof
:reportError
echo.
- echo %ERROR%
+ echo ERROR: %ERROR%
+ echo Please refer to the svrREADME documentation.
echo.
- echo %ERROR% >> %GHIDRA_HOME%\wrapper.log
+ echo ERROR: %ERROR% >> %GHIDRA_HOME%\wrapper.log
exit /B 1
:eof
diff --git a/Ghidra/RuntimeScripts/Windows/support/launch.bat b/Ghidra/RuntimeScripts/Windows/support/launch.bat
index 9cfdfb5d00..5b31ec4977 100644
--- a/Ghidra/RuntimeScripts/Windows/support/launch.bat
+++ b/Ghidra/RuntimeScripts/Windows/support/launch.bat
@@ -42,7 +42,7 @@ set "SUPPORT_DIR=%SUPPORT_DIR:~0,-1%"
:: Ensure Ghidra path doesn't contain illegal characters
if not "%SUPPORT_DIR:!=%"=="%SUPPORT_DIR%" (
- echo Ghidra path cannot contain a "!" character.
+ echo ERROR: Ghidra path cannot contain a "!" character.
set ERRORLEVEL=1
goto exit1
)
@@ -73,7 +73,7 @@ IF DEFINED ARG (
)
if not "%CLASSNAME%" == "" (goto continue1)
-echo Incorrect launch usage - missing argument^(s^)
+echo ERROR: Incorrect launch usage - missing argument^(s^)
goto showUsage
:continue1
@@ -99,7 +99,7 @@ if not exist "%LS_CPATH%" (
set "LS_CPATH=%INSTALL_DIR%\GhidraBuild\LaunchSupport\build\libs\LaunchSupport.jar"
)
if not exist "%LS_CPATH%" (
- echo Cannot launch from repo because Ghidra has not been compiled with Eclipse or Gradle.
+ echo ERROR: Cannot launch from repo because Ghidra has not been compiled with Eclipse or Gradle.
set ERRORLEVEL=1
goto exit1
)
@@ -112,33 +112,49 @@ if exist "%USERPROFILE%" (
set VMARG_LIST=%VMARG_LIST% -Duser.home="%USERPROFILE%"
)
-:: Make sure some kind of java is on the path. It's required to run the LaunchSupport program.
-java -version >nul 2>nul
-if not %ERRORLEVEL% == 0 (
- echo Java runtime not found. Please refer to the Ghidra Installation Guide's Troubleshooting section.
- goto exit1
-)
+:: check for java based upon PATH
+set JAVA_CMD=java.exe
+java.exe -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto continue3
+
+:: check for java based upon JAVA_HOME environment variable
+if not defined JAVA_HOME goto javaNotFound
+set "JAVA_CMD=%JAVA_HOME%\bin\java.exe"
+"%JAVA_CMD%" -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto continue3
+echo WARNING: JAVA_HOME environment variable is set to an invalid directory: %JAVA_HOME%
+
+:javaNotFound
+echo.
+echo ERROR: The 'java' command could not be found in your PATH or with JAVA_HOME.
+echo Please refer to the Ghidra Installation Guide's Troubleshooting section.
+set ERRORLEVEL=1
+goto exit1
+
+:: Use LaunchSupport to locate supported java runtime
+:continue3
:: Get the JDK that will be used to launch Ghidra
-set JAVA_HOME=
-for /f "delims=*" %%i in ('java -cp "%LS_CPATH%" LaunchSupport "%INSTALL_DIR%" %JAVA_TYPE_ARG% -save') do set JAVA_HOME=%%i
-if "%JAVA_HOME%" == "" (
+set LS_JAVA_HOME=
+for /f "delims=*" %%i in ('call "%JAVA_CMD%" -cp "%LS_CPATH%" LaunchSupport "%INSTALL_DIR%" %JAVA_TYPE_ARG% -save') do set LS_JAVA_HOME=%%i
+if "%LS_JAVA_HOME%" == "" (
:: No JDK has been setup yet. Let the user choose one.
- java -cp "%LS_CPATH%" LaunchSupport "%INSTALL_DIR%" %JAVA_TYPE_ARG% -ask
+ "%JAVA_CMD%" -cp "%LS_CPATH%" LaunchSupport "%INSTALL_DIR%" %JAVA_TYPE_ARG% -ask
:: Now that the user chose one, try again to get the JDK that will be used to launch Ghidra
- for /f "delims=*" %%i in ('java -cp "%LS_CPATH%" LaunchSupport "%INSTALL_DIR%" %JAVA_TYPE_ARG% -save') do set JAVA_HOME=%%i
- if "!JAVA_HOME!" == "" (
+ for /f "delims=*" %%i in ('call "%JAVA_CMD%" -cp "%LS_CPATH%" LaunchSupport "%INSTALL_DIR%" %JAVA_TYPE_ARG% -save') do set LS_JAVA_HOME=%%i
+ if "!LS_JAVA_HOME!" == "" (
echo.
- echo Failed to find a supported JDK. Please refer to the Ghidra Installation Guide's Troubleshooting section.
+ echo ERROR: Failed to find a supported JDK.
+ echo Please refer to the Ghidra Installation Guide's Troubleshooting section.
set ERRORLEVEL=1
goto exit1
)
)
-set "JAVA_CMD=%JAVA_HOME%\bin\java"
+set "JAVA_CMD=%LS_JAVA_HOME%\bin\java"
:: Get the configurable VM arguments from the launch properties
-for /f "delims=*" %%i in ('java -cp "%LS_CPATH%" LaunchSupport "%INSTALL_DIR%" -vmargs') do set VMARG_LIST=!VMARG_LIST! %%i
+for /f "delims=*" %%i in ('call "%JAVA_CMD%" -cp "%LS_CPATH%" LaunchSupport "%INSTALL_DIR%" -vmargs') do set VMARG_LIST=!VMARG_LIST! %%i
:: Set Max Heap Size if specified
if not "%MAXMEM%"=="" (
@@ -165,22 +181,22 @@ if "%DEBUG%"=="y" (
set VMARG_LIST=!VMARG_LIST! -Dlog4j.configurationFile="!DEBUG_LOG4J!"
set VMARG_LIST=!VMARG_LIST! -agentlib:jdwp=transport=dt_socket,server=y,suspend=!SUSPEND!,address=!DEBUG_ADDRESS!
- goto continue3
+ goto continue4
)
if "%MODE%"=="fg" (
- goto continue3
+ goto continue4
)
if "%MODE%"=="bg" (
set BACKGROUND=y
- goto continue3
+ goto continue4
)
-echo "Incorrect launch usage - invalid launch mode: %MODE%"
+echo "ERROR: Incorrect launch usage - invalid launch mode: %MODE%"
exit /B 1
-:continue3
+:continue4
set CMD_ARGS=%FORCE_JAVA_VERSION% %JAVA_USER_HOME_DIR_OVERRIDE% %VMARG_LIST% -cp "%CPATH%" ghidra.Ghidra %CLASSNAME% %ARGS%
diff --git a/GhidraBuild/LaunchSupport/src/main/java/LaunchSupport.java b/GhidraBuild/LaunchSupport/src/main/java/LaunchSupport.java
index 342daa08e7..36d6078c76 100644
--- a/GhidraBuild/LaunchSupport/src/main/java/LaunchSupport.java
+++ b/GhidraBuild/LaunchSupport/src/main/java/LaunchSupport.java
@@ -29,7 +29,7 @@ import ghidra.launch.JavaFinder.JavaFilter;
* rather than in OS-specific scripts.
*/
public class LaunchSupport {
-
+
private static final int EXIT_SUCCESS = 0;
private static final int EXIT_FAILURE = 1;
@@ -37,13 +37,18 @@ public class LaunchSupport {
* {@link LaunchSupport} entry point. Uses standard exit codes to tell the user if
* the desired operation succeeded for failed.
*
- * @param args [INSTALL_DIR] [-java_home | -jdk_home | -vmargs] [-ask | -save]
+ * @param args [INSTALL_DIR] [-java_home | -jdk_home | -vmargs | -java_home_check <path>] [-ask | -save]
*
- * - -java_home: Get Java home (JDK or JRE)
- * - -jdk_home: Get Java home (JDK only)
- * - -vmargs: Get JVM arguments
- * - -ask: Interactively ask the user to choose a Java home
- * - -save: Save Java home to file for future use
+ * - -java_home: Get Java home (JDK or JRE) and output on stdout.
+ * - -jdk_home: Get Java home (JDK only) and output on stdout.
+ * - -jdk_home_check: Verify that the specified Java home directory contains a
+ * supported version of java. No output is produced.
+ * - -vmargs: Get JVM arguments and output on stdout (one per line).
+ *
+ * Optional arguments supported by -java_home and -jdk_home:
+ *
+ * - -ask: Interactively ask the user to choose a Java home.
+ * - -save: Save Java home to file for future use.
*
*/
public static void main(String[] args) {
@@ -55,14 +60,25 @@ public class LaunchSupport {
System.err.println("LaunchSupport expected 2 to 4 arguments but got " + args.length);
System.exit(exitCode);
}
-
+
// Parse command line arguments
- String installDirPath = args[0];
- String mode = args[1];
+ int argIx = 0;
+ String installDirPath = args[argIx++];
+ String mode = args[argIx++];
+ String checkPath = null;
+ if ("-java_home_check".equals(mode)) {
+ checkPath = args[argIx++];
+ }
+
+ if (!"-java_home".equals(mode) && !"-jdk_home".equals(mode) && argIx != args.length) {
+ System.err.println("LaunchSupport received illegal argument: " + args[argIx]);
+ System.exit(exitCode);
+ }
+
boolean ask = false;
boolean save = false;
- for (int i = 2; i < args.length; i++) {
+ for (int i = argIx; i < args.length; i++) {
if (args[i].equals("-ask")) {
ask = true;
}
@@ -76,7 +92,7 @@ public class LaunchSupport {
}
try {
-
+
File installDir = new File(installDirPath).getCanonicalFile(); // change relative path to absolute
AppConfig appConfig = new AppConfig(installDir);
JavaFinder javaFinder = JavaFinder.create();
@@ -86,6 +102,11 @@ public class LaunchSupport {
case "-java_home":
exitCode = handleJavaHome(appConfig, javaFinder, JavaFilter.ANY, ask, save);
break;
+ case "-java_home_check":
+ if (appConfig.isSupportedJavaHomeDir(new File(checkPath), JavaFilter.ANY)) {
+ exitCode = EXIT_SUCCESS;
+ }
+ break;
case "-jdk_home":
exitCode =
handleJavaHome(appConfig, javaFinder, JavaFilter.JDK_ONLY, ask, save);
@@ -128,6 +149,18 @@ public class LaunchSupport {
return findJavaHome(appConfig, javaFinder, javaFilter, save);
}
+ private static void logJavaHomeError(File javaHomeDir, boolean isError, String source) {
+ String level = isError ? "ERROR: " : "WARNING: ";
+ if (!javaHomeDir.isDirectory()) {
+ System.err
+ .println(level + source + " specifies non-existing directory: " + javaHomeDir);
+ }
+ else {
+ System.err.println(
+ level + source + " specifies unsupported java version: " + javaHomeDir);
+ }
+ }
+
/**
* Handles finding a Java home directory to use for the launch. If one is successfully
* found, its path is printed to STDOUT and an exit code that indicates success is
@@ -158,8 +191,23 @@ public class LaunchSupport {
System.out.println(javaHomeDir);
return EXIT_SUCCESS;
}
+ if (javaHomeDir != null) {
+ logJavaHomeError(javaHomeDir, true,
+ launchProperties.getLaunchPropertiesFile().getAbsolutePath() + ", " +
+ LaunchProperties.JAVA_HOME_OVERRIDE);
+ }
- // PRIORITY 2: Java on PATH
+ // PRIORITY 2: Java specified by JAVA_HOME environment
+ String javaHome = System.getenv("JAVA_HOME");
+ if (javaHome != null) {
+ javaHomeDir = new File(javaHome);
+ if (appConfig.isSupportedJavaHomeDir(javaHomeDir, javaFilter)) {
+ System.out.println(javaHomeDir);
+ return EXIT_SUCCESS;
+ }
+ }
+
+ // PRIORITY 3: Java on PATH
// This program (LaunchSupport) was started with the Java on the PATH. Try to use this one
// next because it is most likely the one that is being upgraded on the user's system.
javaHomeDir = javaFinder.findSupportedJavaHomeFromCurrentJavaHome(appConfig, javaFilter);
@@ -171,7 +219,7 @@ public class LaunchSupport {
return EXIT_SUCCESS;
}
- // PRIORITY 3: Last used Java
+ // PRIORITY 4: Last used Java
// Check to see if a prior launch resulted in that Java being saved. If so, try to use that.
javaHomeDir = appConfig.getSavedJavaHome();
if (appConfig.isSupportedJavaHomeDir(javaHomeDir, javaFilter)) {
@@ -179,7 +227,7 @@ public class LaunchSupport {
return EXIT_SUCCESS;
}
- // PRIORITY 4: Find all supported Java installations, and use the newest.
+ // PRIORITY 5: Find all supported Java installations, and use the newest.
List javaHomeDirs =
javaFinder.findSupportedJavaHomeFromInstallations(appConfig, javaFilter);
if (!javaHomeDirs.isEmpty()) {
@@ -191,6 +239,11 @@ public class LaunchSupport {
return EXIT_SUCCESS;
}
+ // Issue warning about incompatible JAVA_HOME
+ if (javaHome != null) {
+ logJavaHomeError(new File(javaHome), false, "JAVA_HOME environment");
+ }
+
return EXIT_FAILURE;
}
@@ -225,9 +278,9 @@ public class LaunchSupport {
}
System.out.println("******************************************************************");
- System.out.println(
- javaName + " " + javaRange + " (" + appConfig.getSupportedArchitecture() +
- "-bit) could not be found and must be manually chosen!");
+ System.out
+ .println(javaName + " " + javaRange + " (" + appConfig.getSupportedArchitecture() +
+ "-bit) could not be found and must be manually chosen!");
System.out.println("******************************************************************");
File javaHomeDir = null;
@@ -287,7 +340,7 @@ public class LaunchSupport {
*/
private static int handleVmArgs(AppConfig appConfig) {
if (appConfig.getLaunchProperties() == null) {
- System.out.println("Launch properties file was not specified!");
+ System.err.println("Launch properties file was not specified!");
return EXIT_FAILURE;
}
diff --git a/GhidraBuild/LaunchSupport/src/main/java/ghidra/launch/LaunchProperties.java b/GhidraBuild/LaunchSupport/src/main/java/ghidra/launch/LaunchProperties.java
index d82634f0a8..b516f00613 100644
--- a/GhidraBuild/LaunchSupport/src/main/java/ghidra/launch/LaunchProperties.java
+++ b/GhidraBuild/LaunchSupport/src/main/java/ghidra/launch/LaunchProperties.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -46,6 +46,7 @@ public class LaunchProperties {
public static String VMARGS_PLATFORM = "VMARGS_" + JavaFinder.getCurrentPlatform();
private Map> propertyMap;
+ private File launchPropertiesFile;
/**
* Creates a new launch properties object from the given launch properties file.
@@ -57,9 +58,19 @@ public class LaunchProperties {
*/
public LaunchProperties(File launchPropertiesFile)
throws FileNotFoundException, IOException, ParseException {
+ this.launchPropertiesFile = launchPropertiesFile;
propertyMap = parseLaunchProperties(launchPropertiesFile);
}
+ /**
+ * Get the launch properties storage file.
+ * NOTE: File is intended for read-only use by application.
+ * @return launch properties file
+ */
+ public File getLaunchPropertiesFile() {
+ return launchPropertiesFile;
+ }
+
/**
* Gets the Java home override directory to use for the launch.
*
diff --git a/GhidraDocs/InstallationGuide.md b/GhidraDocs/InstallationGuide.md
index 952ca70946..2ab27e33e2 100644
--- a/GhidraDocs/InstallationGuide.md
+++ b/GhidraDocs/InstallationGuide.md
@@ -93,12 +93,14 @@ using any unzip program (built-in OS utilities, 7-Zip, WinZip, WinRAR, etc).
### Java Notes
* Ghidra requires a [supported](#minimum-requirements) version of a Java Runtime and Development Kit
- on the PATH to run. However, if there is a version of Java on the PATH that Ghidra does not
- support, it will use that version of Java (if 1.8 or later) to assist in locating a supported
- version on your system. If one cannot be automatically located, the user will be prompted to
- enter a path to the Java home directory to use (the Java home directory is the parent directory of
- Java's `bin` directory). This minimizes the impact Ghidra has on pre-existing configurations of
- Java that other software may rely on.
+ on the PATH, or specified by the JAVA_HOME environment variable. If JAVA_HOME is specified
+ it will take precedence over the PATH. If the version of Java found does not satisfy the
+ [minimum version](#minimum-requirements) required, it will use that version of Java
+ (if 1.8 or later) to assist in locating a supported version on your system. If one cannot
+ be automatically located the user will be prompted to enter a path to the Java home directory
+ to use (the Java home directory is the parent directory of Java's `bin` directory). This
+ minimizes the impact Ghidra has on pre-existing configurations of Java that other software may
+ rely on.
* Depending on your operating system, it may be possible to find and install a
[supported](#minimum-requirements) version of a Java Runtime and Development Kit through
@@ -151,8 +153,8 @@ using any unzip program (built-in OS utilities, 7-Zip, WinZip, WinRAR, etc).
version that Ghidra automatically locates. To force Ghidra to launch with a specific version of
Java, set the `JAVA_HOME_OVERRIDE` property in the `support/launch.properties` file. If this
property is set to an incompatible version of Java, Ghidra will revert to automatically locating a
- compatible version. Note that _some_ Java must still be on the PATH in order for Ghidra to use
- the `JAVA_HOME_OVERRIDE` property.
+ compatible version. Note that _some_ Java must still be on the PATH or specified by JAVA_HOME
+ environment variable in order for Ghidra to use the `JAVA_HOME_OVERRIDE` property.
### Debugger Notes
The Debugger now uses Python to connect to the host platform's native debuggers. This requires
@@ -381,16 +383,18 @@ Ghidra Server.
When launching Ghidra with the provided scripts in `` and
`/support`, you may encounter the following error messages:
-* __Problem:__ _Java runtime not found._
- * __Solution:__ A Java runtime (java/java.exe) is required to be on the system PATH. Please see
- the [requirements](#minimum-requirements) section for what version of Java must be pre-installed
+* __Problem:__ _The 'java' command could not be found in your PATH or with JAVA_HOME._
+ * __Solution:__ A Java runtime (java/java.exe) is required to be on the system PATH or the Java
+ installation directory specified by the JAVA_HOME environment variable. Please see the
+ [requirements](#minimum-requirements) section for what version of Java must be pre-installed
for Ghidra to launch.
* __Problem:__ _Failed to find a supported JDK._
- * __Solution:__ The Ghidra launch script uses the Java runtime on the system PATH to find a
- supported version of a Java Development Kit (JDK) that Ghidra needs to complete its launch.
- Please see the [requirements](#minimum-requirements) section for what version of JDK must be
- pre-installed for Ghidra to launch.
+ * __Solution:__ The Ghidra launch script uses the Java runtime on the system PATH or specified
+ by the JAVA_HOME environment variable to find a supported version of a Java Development Kit
+ (JDK) that Ghidra needs to complete its launch. Please see the
+ [requirements](#minimum-requirements) section for what version of JDK must be pre-installed
+ for Ghidra to launch.
* __Problem:__ _Exited with error. Run in foreground (fg) mode for more details._
* __Solution:__ Ghidra failed to launch in the background and the error message describing the