GP-5161 Corrected Ghidra Server CME, document updates, and launch script improvements to control Java home determination.

This commit is contained in:
ghidra1 2025-01-03 13:19:43 -05:00
parent dacc9b226d
commit 5f338723b6
9 changed files with 444 additions and 249 deletions

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 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.RemoteException;
import java.rmi.server.UnicastRemoteObject; import java.rmi.server.UnicastRemoteObject;
import java.rmi.server.Unreferenced; import java.rmi.server.Unreferenced;
import java.util.HashMap; import java.util.*;
import java.util.LinkedList;
import db.buffers.*; import db.buffers.*;
import ghidra.framework.remote.*; import ghidra.framework.remote.*;
@ -118,7 +117,9 @@ public class RepositoryHandleImpl extends UnicastRemoteObject
try { try {
repository.log(null, "Clearning " + transientCheckouts.size() + " transiet checkouts", repository.log(null, "Clearning " + transientCheckouts.size() + " transiet checkouts",
currentUser); currentUser);
for (String pathname : transientCheckouts.keySet()) {
ArrayList<String> pathnames = new ArrayList<>(transientCheckouts.keySet());
for (String pathname : pathnames) {
int index = pathname.lastIndexOf(FileSystem.SEPARATOR_CHAR); int index = pathname.lastIndexOf(FileSystem.SEPARATOR_CHAR);
String parentPath = FileSystem.SEPARATOR; String parentPath = FileSystem.SEPARATOR;
if (index != 0) { if (index != 0) {
@ -127,10 +128,12 @@ public class RepositoryHandleImpl extends UnicastRemoteObject
String itemName = pathname.substring(index + 1); String itemName = pathname.substring(index + 1);
ItemCheckoutStatus transientCheckout = transientCheckouts.get(pathname); ItemCheckoutStatus transientCheckout = transientCheckouts.get(pathname);
if (transientCheckout != null) {
// Since dropped transient checkouts could occur in large volume due to headless // Since dropped transient checkouts could occur in large volume due to headless
// processing, don't bother sending notification // processing, don't bother sending notification
terminateCheckout(parentPath, itemName, transientCheckout.getCheckoutId(), false); terminateCheckout(parentPath, itemName, transientCheckout.getCheckoutId(),
false);
}
} }
} }
catch (IOException e) { catch (IOException e) {

View file

@ -60,6 +60,7 @@ typewriter {
<UL> <UL>
<LI><a href="#checkinFailures">Failures Creating Repository Folders / Checking in Files</a></LI> <LI><a href="#checkinFailures">Failures Creating Repository Folders / Checking in Files</a></LI>
<LI><a href="#connectErrors">Client/Server connection errors</a></LI> <LI><a href="#connectErrors">Client/Server connection errors</a></LI>
<LI><a href="#windowsWatchService">MS Windows - ERROR Incorrect function (WindowsWatchService)</a></LI>
<LI><a href="#windowsMissingTempDirectory">MS Windows - ERROR Missing Temp Directory</a></LI> <LI><a href="#windowsMissingTempDirectory">MS Windows - ERROR Missing Temp Directory</a></LI>
<LI><a href="#windows7and8_scriptErrors">MS Windows 7 and 8 - ghidraSvr.bat, svrInstall.bat, <LI><a href="#windows7and8_scriptErrors">MS Windows 7 and 8 - ghidraSvr.bat, svrInstall.bat,
or svrUninstall.bat Error</a></LI> or svrUninstall.bat Error</a></LI>
@ -95,13 +96,7 @@ run a second concurrent instance may lead to difficulties and is not supported.
<b>NOTE</b>: It is highly recommended that the installation files for Ghidra reside on a local drive <b>NOTE</b>: It is highly recommended that the installation files for Ghidra reside on a local drive
and that the intended Ghidra Server process owner is granted full access to the Ghidra installation and that the intended Ghidra Server process owner is granted full access to the Ghidra installation
directory (this is frequently not the case for NFS/SMB mounted home directories). directory (this is frequently not the case for NFS/SMB mounted home directories).
</P> </P>
<P>
<b>NOTE</b>: 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.
</P>
<P> <P>
You may also refer to the <typewriter>InstallationGuide.html</typewriter> file within the You may also refer to the <typewriter>InstallationGuide.html</typewriter> file within the
@ -137,8 +132,20 @@ location and other associated options.
</P> </P>
<P> <P>
You should generally avoid using the default repositories location and specify a location outside It is highly recommended that you specify a repositories directory outside of your
your installation directory using an absolute path specification. 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.
</P>
<P>
<b>NOTE:</b> 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 <b>svrAdmin</b> command. If a running
server fails to process queued <b>svrAdmin</b> command requests, the repository native filesystem
may be the cause.
</P> </P>
<P> <P>
@ -401,7 +408,7 @@ are not currently supported.
<LI><typewriter>-autoProvision</typewriter><br>Enable the auto-creation of new Ghidra Server <LI><typewriter>-autoProvision</typewriter><br>Enable the auto-creation of new Ghidra Server
users when they successfully authenticate to the server (-a1 and -a4 modes only). 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 Users removed from the authentication provider (e.g., Active Directory) will need to be
deleted manually from the Ghidra Server using svrAdmin command.</LI> deleted manually from the Ghidra Server using <b>svrAdmin</b> command.</LI>
<br> <br>
<LI><typewriter>-anonymous</typewriter><br>Enable anonymous access support for Ghidra Server <LI><typewriter>-anonymous</typewriter><br>Enable anonymous access support for Ghidra Server
and its repositories. Only those repositories which specifically enable anonymous access will be and its repositories. Only those repositories which specifically enable anonymous access will be
@ -555,8 +562,26 @@ are not currently supported.
<P> <P>
The Ghidra Server may be installed as an automatic service by executing the The Ghidra Server may be installed as an automatic service by executing the
<typewriter>svrInstall</typewriter> script. Once installed, the server will start automatically <typewriter>svrInstall</typewriter> 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
<a href="#linux_mac_uninstall">Uninstall Service</a>).
</P> </P>
<P>
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 <typewriter>ghidraSvr</typewriter> 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.
</P>
<P>Example setting of GHIDRA_JAVA_HOME within <typewriter>ghidraSvr</typewriter> script:
<PRE>
GHIDRA_JAVA_HOME=/usr/lib/jvm/java-21-openjdk
</PRE>
<P> <P>
If it is preferred to run the service with a dedicated local user account, the following If it is preferred to run the service with a dedicated local user account, the following
entry may be added to the <i>server.conf</i> file with the appropriate account specified in entry may be added to the <i>server.conf</i> file with the appropriate account specified in
@ -567,7 +592,7 @@ are not currently supported.
installation of the Ghidra Server service. installation of the Ghidra Server service.
</P> </P>
<PRE> <PRE>
wrapper.app.account=&lt;uid&gt; wrapper.app.account=&lt;uid&gt;
</PRE> </PRE>
<P> <P>
It is also important that the repositories directory and Ghidra installation files It is also important that the repositories directory and Ghidra installation files
@ -582,14 +607,20 @@ to run as <i>root</i> and monitor/manage the Java process.
<typewriter>svrUninstall</typewriter> script. <typewriter>svrUninstall</typewriter> script.
</P> </P>
<P> <P>
<b>NOTE</b>: It is very important that you uninstall the service prior to doing any of the following <b>IMPORTANT</b>: It is very important that you uninstall the Ghidra Server service using the
activities: 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:
<UL> <UL>
<LI>deleting or upgrading the Ghidra installation</LI> <LI>deleting or upgrading the Ghidra installation</LI>
<LI>moving/renaming the Ghidra installation directory</LI> <LI>moving/renaming the Ghidra installation directory</LI>
</UL> </UL>
</P> </P>
<P>
<b>NOTE</b>: The service control mechanism for Linux changed with the Ghidra 11.2 release.
The <typewriter>init.d</typewriter> mechanism was previously used in all cases, whereas the
<typewriter>systemd</typewriter> service mechanism may now used based upon YAJSW preference.
</P>
(<a href="#top">Back to Top</a>) (<a href="#top">Back to Top</a>)
<div style="border-top: 4px double; margin-top: 1em; padding-top: 1em;"> </div> <div style="border-top: 4px double; margin-top: 1em; padding-top: 1em;"> </div>
@ -1007,6 +1038,14 @@ newer SSL/TLS enabled Ghidra Server registry, the following connection error wil
<PRE> <PRE>
non-JRMP server at remote endpoint non-JRMP server at remote endpoint
</PRE> </PRE>
</P>
<br>
<a name="windowsWatchService"><h3><u>MS Windows - ERROR Incorrect function (WindowsWatchService)</u></h3></a>
<P>
The Ghidra Server employs a file system watcher service for the repositories directory which must
reside within a locally mounted NTFS or ReFS filesystem.
</P>
<br> <br>
<a name="windowsMissingTempDirectory"><h3><u>MS Windows - ERROR Missing Temp Directory</u></h3></a> <a name="windowsMissingTempDirectory"><h3><u>MS Windows - ERROR Missing Temp Directory</u></h3></a>

View file

@ -5,13 +5,24 @@
# Usage: ghidraSvr [ console | status | install | uninstall | start | stop | restart ] # 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 # The Java 21 (or later) runtime installation must either be on the system path, specified by the
# by setting the JAVA_HOME environment variable. If not using a formally installed Java # JAVA_HOME environment variable or preferably set explicitly with the GHIDRA_JAVA_HOME variable
# runtime which has been configured into the system PATH ahead of other Java installations # below. Since this script may be used during service initialization, reliance on environmental
# it may be necessary to explicitly specify the path to the installation by setting JAVA_HOME # settings such as JAVA_HOME may be problematic. It is also important to note that once installed
# below: # 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 OPTION=$1
@ -25,29 +36,30 @@ usage() {
adminFail() { adminFail() {
echo 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 echo
exit 1 exit 1
} }
reportError() { reportError() {
echo echo
echo "$1" echo -e "ERROR: $1"
echo "Please refer to the svrREADME documentation."
echo echo
echo "$1" >> "${GHIDRA_HOME}/wrapper.log" echo -e "ERROR: $1" >> "${GHIDRA_HOME}/wrapper.log"
exit 1 exit 1
} }
if [ "$OPTION" == "" ]; then if [ "${OPTION}" == "" ]; then
usage usage
fi fi
if [ "$EUID" != "0" ]; then if [ "${EUID}" != "0" ]; then
if [ "$OPTION" == "start" ]; then adminFail if [ "${OPTION}" == "start" ]; then adminFail
elif [ "$OPTION" == "stop" ]; then adminFail elif [ "${OPTION}" == "stop" ]; then adminFail
elif [ "$OPTION" == "install" ]; then adminFail elif [ "${OPTION}" == "install" ]; then adminFail
elif [ "$OPTION" == "uninstall" ]; then adminFail elif [ "${OPTION}" == "uninstall" ]; then adminFail
elif [ "$OPTION" == "restart" ]; then adminFail elif [ "${OPTION}" == "restart" ]; then adminFail
fi fi
fi fi
@ -55,7 +67,7 @@ APP_NAME="ghidraSvr"
APP_LONG_NAME="Ghidra Server" APP_LONG_NAME="Ghidra Server"
MODULE_DIR="Ghidra/Features/GhidraServer" MODULE_DIR="Ghidra/Features/GhidraServer"
WRAPPER_NAME_PREFIX=yajsw WRAPPER_NAME_PREFIX=yajsw
SERVICE_NAME=org.rzo.yajsw.$APP_NAME SERVICE_NAME=org.rzo.yajsw.${APP_NAME}
WRAPPER_TMPDIR="${TMPDIR:-/tmp}" WRAPPER_TMPDIR="${TMPDIR:-/tmp}"
# Resolve symbolic link if present and get the directory this script lives in. # 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%/*}" SCRIPT_DIR="${SCRIPT_FILE%/*}"
# Ensure Ghidra path doesn't contain illegal characters # Ensure Ghidra path doesn't contain illegal characters
if [[ "$SCRIPT_DIR" = *"!"* ]]; then if [[ "${SCRIPT_DIR}" = *"!"* ]]; then
echo "Ghidra path cannot contain a \"!\" character." echo "Ghidra path cannot contain a \"!\" character."
exit 1 exit 1
fi fi
@ -76,7 +88,7 @@ cd "${SCRIPT_DIR}"
SCRIPT_DIR="$(pwd)" SCRIPT_DIR="$(pwd)"
OS="$(uname -s)" OS="$(uname -s)"
if [ "$OS" = "Darwin" ]; then if [ "${OS}" = "Darwin" ]; then
OS_DIRNAME="osx64" OS_DIRNAME="osx64"
else else
OS_DIRNAME="linux64" OS_DIRNAME="linux64"
@ -117,33 +129,48 @@ if [ ! -d "${WRAPPER_HOME}" -o ! -f "${WRAPPER_HOME}/wrapper.jar" ]; then
exit 1 exit 1
fi 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. # Determine the Java command to use to start the JVM.
JAVA_CMD=java JAVA_CMD=
if [ -n "$JAVA_HOME" ] ; then if [ -n "${GHIDRA_JAVA_HOME}" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # Identify java command from GHIDRA_JAVA_HOME
# IBM's JDK on AIX uses strange locations for the executables JAVA_CMD="${GHIDRA_JAVA_HOME}/bin/java"
JAVA_CMD="$JAVA_HOME/jre/sh/java" if [ ! -x "${JAVA_CMD}" ] ; then
else reportError "The ghidraSvr script GHIDRA_JAVA_HOME variable is set to an invalid directory: ${GHIDRA_JAVA_HOME}"
JAVA_CMD="$JAVA_HOME/bin/java" fi
fi
if [ ! -x "$JAVA_CMD" ] ; then $("${JAVA_CMD}" -cp "${LS_CPATH}" LaunchSupport "${GHIDRA_HOME}" -java_home_check "${GHIDRA_JAVA_HOME}")
reportError "ERROR: JAVA_HOME is set to an invalid directory: $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 fi
else else
JAVA_CMD="java" # Identify java command from either JAVA_HOME or PATH, try PATH first
which java >/dev/null 2>&1 || reportError "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH." JAVA_CMD=
fi 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_CMD="${LS_JAVA_HOME}/bin/java"
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."
fi fi
JAVA_CMD="${JAVA_HOME}/bin/java"
VMARGS=() VMARGS=()
VMARGS+=("-Djna_tmpdir=${WRAPPER_TMPDIR}") VMARGS+=("-Djna_tmpdir=${WRAPPER_TMPDIR}")
VMARGS+=("-Djava.io.tmpdir=${WRAPPER_TMPDIR}") VMARGS+=("-Djava.io.tmpdir=${WRAPPER_TMPDIR}")
@ -151,14 +178,14 @@ VMARGS+=("-Djava.io.tmpdir=${WRAPPER_TMPDIR}")
enableForkHack() { enableForkHack() {
# use of fork_hack only needed for Mac OS X # use of fork_hack only needed for Mac OS X
if [ "$OS" != "Darwin" ]; then if [ "${OS}" != "Darwin" ]; then
return 0 return 0
fi fi
# watch out for revisions to the associated fork_hack comment in server.conf # watch out for revisions to the associated fork_hack comment in server.conf
# that could throw this off # that could throw this off
HAS_FORK_HACK_LINE="$(grep "wrapper.fork_hack=" "${WRAPPER_CONF}")" 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 if [ "${HAS_FORK_HACK_LINE}" = "wrapper.fork_hack=true" ]; then
return 0 return 0
fi fi
@ -200,81 +227,81 @@ checkInstall() {
} }
console() { console() {
echo "Running ${APP_LONG_NAME}..." 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}" 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() { start() {
echo "Starting ${APP_LONG_NAME}..." 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}" 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() { stopit() {
echo "Stopping ${APP_LONG_NAME}..." 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}" 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() { install() {
echo "Installing ${APP_LONG_NAME}..." 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}" 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() { uninstall() {
echo "Uninstalling ${APP_LONG_NAME}..." 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}" 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() { 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 case "$1" in
'console') 'console')
enableForkHack enableForkHack
console console
;; ;;
'status') 'status')
status status
;; ;;
'start') 'start')
checkInstall checkInstall
if [ $? = 0 ]; then if [ $? = 0 ]; then
start start
fi fi
;; ;;
'stop') 'stop')
checkInstall checkInstall
if [ $? = 0 ]; then if [ $? = 0 ]; then
stopit stopit
fi fi
;; ;;
'restart') 'restart')
checkInstall checkInstall
if [ $? = 0 ]; then if [ $? = 0 ]; then
stopit stopit
start start
fi fi
;; ;;
'install') 'install')
enableForkHack enableForkHack
install install
start start
;; ;;
'uninstall') 'uninstall')
checkInstall checkInstall
if [ $? = 0 ]; then if [ $? = 0 ]; then
uninstall uninstall
fi fi
;; ;;
*) *)
usage usage
;; ;;
esac esac

View file

@ -1,18 +1,18 @@
#!/usr/bin/env bash #!/usr/bin/env bash
## ### ## ###
# IP: GHIDRA # IP: GHIDRA
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
# You may obtain a copy of the License at # You may obtain a copy of the License at
# #
# http://www.apache.org/licenses/LICENSE-2.0 # http://www.apache.org/licenses/LICENSE-2.0
# #
# Unless required by applicable law or agreed to in writing, software # Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, # distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
## ##
umask 027 umask 027
@ -21,31 +21,30 @@ function showUsage() {
echo "Usage: $0 <mode> <java-type> <name> <max-memory> \"<vmarg-list>\" <app-classname> <app-args>... " echo "Usage: $0 <mode> <java-type> <name> <max-memory> \"<vmarg-list>\" <app-classname> <app-args>... "
echo " <mode>: fg run as foreground process in current shell" echo " <mode>: fg run as foreground process in current shell"
echo " bg run as background process in new 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 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 " 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 " 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 " override default debug address of 127.0.0.1:18001"
echo " <java-type>: jdk requires JDK to run" echo " <java-type>: 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 " <name>: application name used for naming console window" echo " <name>: application name used for naming console window"
echo " <max-memory>: maximum memory heap size in MB (e.g., 768M or 2G). Use empty \"\" if default" echo " <max-memory>: 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 " should be used. This will generally be upto 1/4 of the physical memory available"
echo " to the OS." echo " to the OS."
echo " <vmarg-list>: pass-thru args (e.g., \"-Xmx512M -Dmyvar=1 -DanotherVar=2\"). Use" echo " <vmarg-list>: 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 " <app-classname>: application classname (e.g., ghidra.GhidraRun )" echo " <app-classname>: application classname (e.g., ghidra.GhidraRun )"
echo " <app-args>...: arguments to be passed to the application" echo " <app-args>...: arguments to be passed to the application"
echo " " echo " "
echo " Example:" echo " Example:"
echo " \"$0\" debug jdk Ghidra 4G \"\" ghidra.GhidraRun" echo " \"$0\" debug jdk Ghidra 4G \"\" ghidra.GhidraRun"
exit 1 exit 1
} }
VMARGS_FROM_CALLER= # Passed in from the outer script as one long string, no spaces
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_SH=() # Defined in this script, added to array
VMARGS_FROM_LAUNCH_PROPS=() # Retrieved from LaunchSupport, added to array VMARGS_FROM_LAUNCH_PROPS=() # Retrieved from LaunchSupport, added to array
ARGS=() ARGS=()
@ -97,7 +96,7 @@ fi
SUPPORT_DIR="${0%/*}" SUPPORT_DIR="${0%/*}"
# Ensure Ghidra path doesn't contain illegal characters # Ensure Ghidra path doesn't contain illegal characters
if [[ "$SUPPORT_DIR" = *"!"* ]]; then if [[ "${SUPPORT_DIR}" = *"!"* ]]; then
echo "Ghidra path cannot contain a \"!\" character." echo "Ghidra path cannot contain a \"!\" character."
exit 1 exit 1
fi fi
@ -119,46 +118,61 @@ else
CPATH="${INSTALL_DIR}/Ghidra/Framework/Utility/build/libs/Utility.jar" CPATH="${INSTALL_DIR}/Ghidra/Framework/Utility/build/libs/Utility.jar"
LS_CPATH="${INSTALL_DIR}/GhidraBuild/LaunchSupport/build/libs/LaunchSupport.jar" LS_CPATH="${INSTALL_DIR}/GhidraBuild/LaunchSupport/build/libs/LaunchSupport.jar"
if ! [ -f "${LS_CPATH}" ]; then 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 exit 1
fi fi
fi fi
DEBUG_LOG4J="${INSTALL_DIR}/Ghidra/RuntimeScripts/Common/support/debug.log4j.xml" DEBUG_LOG4J="${INSTALL_DIR}/Ghidra/RuntimeScripts/Common/support/debug.log4j.xml"
fi fi
# Make sure some kind of java is on the path. It's required to run the LaunchSupport program. # Identify java command from either JAVA_HOME or PATH, try PATH first
if ! [ -x "$(command -v java)" ] ; then JAVA_CMD=
echo "Java runtime not found. Please refer to the Ghidra Installation Guide's Troubleshooting section." 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 exit 1
fi fi
# Get the JDK that will be used to launch Ghidra # 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 [ ! $? -eq 0 ]; then
# If fd 0 (stdin) isn't a tty, fail because we can't prompt the user # If fd 0 (stdin) isn't a tty, fail because we can't prompt the user
if [ ! -t 0 ]; then if [ ! -t 0 ]; then
echo 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 exit 1
fi fi
# No JDK has been setup yet. Let the user choose one. # 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 # 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 if [ ! $? -eq 0 ]; then
echo 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 exit 1
fi fi
fi fi
JAVA_CMD="${JAVA_HOME}/bin/java" JAVA_CMD="${LS_JAVA_HOME}/bin/java"
# Get the configurable VM arguments from the launch properties # Get the configurable VM arguments from the launch properties
while IFS=$'\r\n' read -r line; do while IFS=$'\r\n' read -r line; do
VMARGS_FROM_LAUNCH_PROPS+=("$line") 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 # Add extra macOS VM arguments
if [ "$(uname -s)" = "Darwin" ]; then if [ "$(uname -s)" = "Darwin" ]; then
@ -194,7 +208,7 @@ elif [ "${MODE}" = "bg" ]; then
BACKGROUND=true BACKGROUND=true
else else
echo "Incorrect launch usage - invalid launch mode: ${MODE}" echo "ERROR: Incorrect launch usage - invalid launch mode: ${MODE}"
exit 1 exit 1
fi fi

View file

@ -1,17 +1,18 @@
@echo off @echo off
rem --------------------------------------------------------------------------------------- :: ---------------------------------------------------------------------------------------
rem Ghidra Server Script (see svrREADME.html for usage details) :: Ghidra Server Script (see svrREADME.html for usage details)
rem Usage: ghidraSvr [ console | status | install | uninstall | start | stop | restart ] :: Usage: ghidraSvr [ console | status | install | uninstall | start | stop | restart ]
rem --------------------------------------------------------------------------------------- :: ---------------------------------------------------------------------------------------
rem The Java 21 (or later) runtime installation must either be on the system path or identified :: The Java 21 (or later) runtime installation must either be on the system path, specified by the
rem by setting the JAVA_HOME environment variable. If not using a formally installed Java :: JAVA_HOME environment variable or preferably set explicitly with the GHIDRA_JAVA_HOME variable
rem runtime which has been configured into the system PATH ahead of other Java installations :: below. Since this script may be used during service initialization, reliance on environmental
rem it may be necessary to explicitly specify the path to the installation by setting JAVA_HOME :: settings such as JAVA_HOME may be problematic. It is also important to note that once installed
rem below: :: 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). :: Sets SERVER_DIR to the directory that contains this file (ghidraSvr.bat).
:: SERVER_DIR will not contain a trailing slash. :: SERVER_DIR will not contain a trailing slash.
@ -23,7 +24,7 @@ rem set "JAVA_HOME="
set "SERVER_DIR=%~dp0" set "SERVER_DIR=%~dp0"
set "SERVER_DIR=%SERVER_DIR:~0,-1%" 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%" ( if not "%SERVER_DIR:!=%"=="%SERVER_DIR%" (
echo Ghidra path cannot contain a "!" character. echo Ghidra path cannot contain a "!" character.
exit /B 1 exit /B 1
@ -56,7 +57,7 @@ set IS_ADMIN=NO
whoami /groups | findstr "S-1-16-12288 " >NUL && set IS_ADMIN=YES whoami /groups | findstr "S-1-16-12288 " >NUL && set IS_ADMIN=YES
if "%IS_ADMIN%"=="NO" ( if "%IS_ADMIN%"=="NO" (
rem The following command options require admin :: The following command options require admin
if "%OPTION%"=="start" goto adminFail if "%OPTION%"=="start" goto adminFail
if "%OPTION%"=="stop" goto adminFail if "%OPTION%"=="stop" goto adminFail
if "%OPTION%"=="install" goto adminFail if "%OPTION%"=="install" goto adminFail
@ -72,11 +73,11 @@ set "WRAPPER_TMPDIR=%TEMP%"
if exist "%SERVER_DIR%\..\Ghidra\" goto normal 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 "GHIDRA_HOME=%SERVER_DIR%\..\..\..\.."
set "WRAPPER_CONF=%SERVER_DIR%\..\..\Common\server\server.conf" set "WRAPPER_CONF=%SERVER_DIR%\..\..\Common\server\server.conf"
set "DATA_DIR=%GHIDRA_HOME%\%MODULE_DIR%\build\data" 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" set "LS_CPATH=%GHIDRA_HOME%\GhidraBuild\LaunchSupport\build\libs\LaunchSupport.jar"
) )
if not exist "%LS_CPATH%" ( 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 goto reportError
) )
@ -101,7 +102,7 @@ set "LS_CPATH=%GHIDRA_HOME%\support\LaunchSupport.jar"
:lab1 :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 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%" set "WRAPPER_HOME=%DATA_DIR%\%WRAPPER_DIRNAME%"
@ -114,34 +115,60 @@ if not exist "%WRAPPER_HOME%\" (
echo Using service wrapper: %WRAPPER_DIRNAME% echo Using service wrapper: %WRAPPER_DIRNAME%
rem Find java.exe :: Check for use of GHIDRA_JAVA_HOME
if defined JAVA_HOME goto findJavaFromJavaHome 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 set java=java.exe
%java% -version >NUL 2>&1 java.exe -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto lab2 if %ERRORLEVEL% equ 0 goto lab2
set ERROR=ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
goto reportError
:findJavaFromJavaHome :: check for java based upon JAVA_HOME environment variable
if not defined JAVA_HOME goto javaNotFound
set "java=%JAVA_HOME%\bin\java.exe" 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 :javaNotFound
set ERROR=ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 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 goto reportError
:: Use LaunchSupport to locate supported java runtime
:lab2 :lab2
:: Get the java that will be used to launch GhidraServer :: Get the java that will be used to launch GhidraServer
set JAVA_HOME= set LS_JAVA_HOME=
for /f "delims=*" %%i in ('call "%java%" -cp "%LS_CPATH%" LaunchSupport "%GHIDRA_HOME%" -java_home') do set JAVA_HOME=%%i for /f "delims=*" %%i in ('call "%java%" -cp "%LS_CPATH%" LaunchSupport "%GHIDRA_HOME%" -java_home') do set LS_JAVA_HOME=%%i
if "%JAVA_HOME%" == "" ( if "%LS_JAVA_HOME%" == "" (
set ERROR=Failed to find a supported Java runtime. Please refer to the Ghidra Installation Guide's Troubleshooting section. set ERROR=Unable to find a supported Java runtime on your system.
goto reportError goto reportError
) )
rem reestablish JAVA path based upon final JAVA_HOME :: reestablish JAVA path based upon LS_JAVA_HOME
set "java=%JAVA_HOME%\bin\java.exe" set "java=%LS_JAVA_HOME%\bin\java.exe"
:: execute command OPTION
:lab3
set VMARGS=-Djava.io.tmpdir="%WRAPPER_TMPDIR%" set VMARGS=-Djava.io.tmpdir="%WRAPPER_TMPDIR%"
set VMARGS=%VMARGS% -Djna_tmpdir="%WRAPPER_TMPDIR%" set VMARGS=%VMARGS% -Djna_tmpdir="%WRAPPER_TMPDIR%"
@ -186,9 +213,10 @@ goto eof
:reportError :reportError
echo. echo.
echo %ERROR% echo ERROR: %ERROR%
echo Please refer to the svrREADME documentation.
echo. echo.
echo %ERROR% >> %GHIDRA_HOME%\wrapper.log echo ERROR: %ERROR% >> %GHIDRA_HOME%\wrapper.log
exit /B 1 exit /B 1
:eof :eof

View file

@ -42,7 +42,7 @@ set "SUPPORT_DIR=%SUPPORT_DIR:~0,-1%"
:: Ensure Ghidra path doesn't contain illegal characters :: Ensure Ghidra path doesn't contain illegal characters
if not "%SUPPORT_DIR:!=%"=="%SUPPORT_DIR%" ( if not "%SUPPORT_DIR:!=%"=="%SUPPORT_DIR%" (
echo Ghidra path cannot contain a "!" character. echo ERROR: Ghidra path cannot contain a "!" character.
set ERRORLEVEL=1 set ERRORLEVEL=1
goto exit1 goto exit1
) )
@ -73,7 +73,7 @@ IF DEFINED ARG (
) )
if not "%CLASSNAME%" == "" (goto continue1) if not "%CLASSNAME%" == "" (goto continue1)
echo Incorrect launch usage - missing argument^(s^) echo ERROR: Incorrect launch usage - missing argument^(s^)
goto showUsage goto showUsage
:continue1 :continue1
@ -99,7 +99,7 @@ if not exist "%LS_CPATH%" (
set "LS_CPATH=%INSTALL_DIR%\GhidraBuild\LaunchSupport\build\libs\LaunchSupport.jar" set "LS_CPATH=%INSTALL_DIR%\GhidraBuild\LaunchSupport\build\libs\LaunchSupport.jar"
) )
if not exist "%LS_CPATH%" ( 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 set ERRORLEVEL=1
goto exit1 goto exit1
) )
@ -112,33 +112,49 @@ if exist "%USERPROFILE%" (
set VMARG_LIST=%VMARG_LIST% -Duser.home="%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. :: check for java based upon PATH
java -version >nul 2>nul set JAVA_CMD=java.exe
if not %ERRORLEVEL% == 0 ( java.exe -version >NUL 2>&1
echo Java runtime not found. Please refer to the Ghidra Installation Guide's Troubleshooting section. if %ERRORLEVEL% equ 0 goto continue3
goto exit1
) :: 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 :: Get the JDK that will be used to launch Ghidra
set JAVA_HOME= set LS_JAVA_HOME=
for /f "delims=*" %%i in ('java -cp "%LS_CPATH%" LaunchSupport "%INSTALL_DIR%" %JAVA_TYPE_ARG% -save') do set JAVA_HOME=%%i 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 "%JAVA_HOME%" == "" ( if "%LS_JAVA_HOME%" == "" (
:: No JDK has been setup yet. Let the user choose one. :: 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 :: 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 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 "!JAVA_HOME!" == "" ( if "!LS_JAVA_HOME!" == "" (
echo. 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 set ERRORLEVEL=1
goto exit1 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 :: 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 :: Set Max Heap Size if specified
if not "%MAXMEM%"=="" ( if not "%MAXMEM%"=="" (
@ -165,22 +181,22 @@ if "%DEBUG%"=="y" (
set VMARG_LIST=!VMARG_LIST! -Dlog4j.configurationFile="!DEBUG_LOG4J!" 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! set VMARG_LIST=!VMARG_LIST! -agentlib:jdwp=transport=dt_socket,server=y,suspend=!SUSPEND!,address=!DEBUG_ADDRESS!
goto continue3 goto continue4
) )
if "%MODE%"=="fg" ( if "%MODE%"=="fg" (
goto continue3 goto continue4
) )
if "%MODE%"=="bg" ( if "%MODE%"=="bg" (
set BACKGROUND=y 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 exit /B 1
:continue3 :continue4
set CMD_ARGS=%FORCE_JAVA_VERSION% %JAVA_USER_HOME_DIR_OVERRIDE% %VMARG_LIST% -cp "%CPATH%" ghidra.Ghidra %CLASSNAME% %ARGS% set CMD_ARGS=%FORCE_JAVA_VERSION% %JAVA_USER_HOME_DIR_OVERRIDE% %VMARG_LIST% -cp "%CPATH%" ghidra.Ghidra %CLASSNAME% %ARGS%

View file

@ -29,7 +29,7 @@ import ghidra.launch.JavaFinder.JavaFilter;
* rather than in OS-specific scripts. * rather than in OS-specific scripts.
*/ */
public class LaunchSupport { public class LaunchSupport {
private static final int EXIT_SUCCESS = 0; private static final int EXIT_SUCCESS = 0;
private static final int EXIT_FAILURE = 1; 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 * {@link LaunchSupport} entry point. Uses standard exit codes to tell the user if
* the desired operation succeeded for failed. * 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 &lt;path&gt;] [-ask | -save]
* <ul> * <ul>
* <li><b>-java_home: </b> Get Java home (JDK or JRE)</li> * <li><b>-java_home: </b> Get Java home (JDK or JRE) and output on stdout.</li>
* <li><b>-jdk_home: </b> Get Java home (JDK only)</li> * <li><b>-jdk_home: </b> Get Java home (JDK only) and output on stdout.</li>
* <li><b>-vmargs: </b> Get JVM arguments</li> * <li><b>-jdk_home_check: </b> Verify that the specified Java home directory contains a
* <li><b>-ask: </b> Interactively ask the user to choose a Java home</li> * supported version of java. No output is produced.</li>
* <li><b>-save: </b> Save Java home to file for future use</li> * <li><b>-vmargs: </b> Get JVM arguments and output on stdout (one per line).</li>
* </ul>
* Optional arguments supported by -java_home and -jdk_home:
* <ul>
* <li><b>-ask: </b> Interactively ask the user to choose a Java home.</li>
* <li><b>-save: </b> Save Java home to file for future use.</li>
* </ul> * </ul>
*/ */
public static void main(String[] args) { 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.err.println("LaunchSupport expected 2 to 4 arguments but got " + args.length);
System.exit(exitCode); System.exit(exitCode);
} }
// Parse command line arguments // Parse command line arguments
String installDirPath = args[0]; int argIx = 0;
String mode = args[1]; 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 ask = false;
boolean save = 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")) { if (args[i].equals("-ask")) {
ask = true; ask = true;
} }
@ -76,7 +92,7 @@ public class LaunchSupport {
} }
try { try {
File installDir = new File(installDirPath).getCanonicalFile(); // change relative path to absolute File installDir = new File(installDirPath).getCanonicalFile(); // change relative path to absolute
AppConfig appConfig = new AppConfig(installDir); AppConfig appConfig = new AppConfig(installDir);
JavaFinder javaFinder = JavaFinder.create(); JavaFinder javaFinder = JavaFinder.create();
@ -86,6 +102,11 @@ public class LaunchSupport {
case "-java_home": case "-java_home":
exitCode = handleJavaHome(appConfig, javaFinder, JavaFilter.ANY, ask, save); exitCode = handleJavaHome(appConfig, javaFinder, JavaFilter.ANY, ask, save);
break; break;
case "-java_home_check":
if (appConfig.isSupportedJavaHomeDir(new File(checkPath), JavaFilter.ANY)) {
exitCode = EXIT_SUCCESS;
}
break;
case "-jdk_home": case "-jdk_home":
exitCode = exitCode =
handleJavaHome(appConfig, javaFinder, JavaFilter.JDK_ONLY, ask, save); handleJavaHome(appConfig, javaFinder, JavaFilter.JDK_ONLY, ask, save);
@ -128,6 +149,18 @@ public class LaunchSupport {
return findJavaHome(appConfig, javaFinder, javaFilter, save); 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 * 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 * 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); System.out.println(javaHomeDir);
return EXIT_SUCCESS; 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 // 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. // next because it is most likely the one that is being upgraded on the user's system.
javaHomeDir = javaFinder.findSupportedJavaHomeFromCurrentJavaHome(appConfig, javaFilter); javaHomeDir = javaFinder.findSupportedJavaHomeFromCurrentJavaHome(appConfig, javaFilter);
@ -171,7 +219,7 @@ public class LaunchSupport {
return EXIT_SUCCESS; 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. // Check to see if a prior launch resulted in that Java being saved. If so, try to use that.
javaHomeDir = appConfig.getSavedJavaHome(); javaHomeDir = appConfig.getSavedJavaHome();
if (appConfig.isSupportedJavaHomeDir(javaHomeDir, javaFilter)) { if (appConfig.isSupportedJavaHomeDir(javaHomeDir, javaFilter)) {
@ -179,7 +227,7 @@ public class LaunchSupport {
return EXIT_SUCCESS; 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<File> javaHomeDirs = List<File> javaHomeDirs =
javaFinder.findSupportedJavaHomeFromInstallations(appConfig, javaFilter); javaFinder.findSupportedJavaHomeFromInstallations(appConfig, javaFilter);
if (!javaHomeDirs.isEmpty()) { if (!javaHomeDirs.isEmpty()) {
@ -191,6 +239,11 @@ public class LaunchSupport {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
// Issue warning about incompatible JAVA_HOME
if (javaHome != null) {
logJavaHomeError(new File(javaHome), false, "JAVA_HOME environment");
}
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -225,9 +278,9 @@ public class LaunchSupport {
} }
System.out.println("******************************************************************"); System.out.println("******************************************************************");
System.out.println( System.out
javaName + " " + javaRange + " (" + appConfig.getSupportedArchitecture() + .println(javaName + " " + javaRange + " (" + appConfig.getSupportedArchitecture() +
"-bit) could not be found and must be manually chosen!"); "-bit) could not be found and must be manually chosen!");
System.out.println("******************************************************************"); System.out.println("******************************************************************");
File javaHomeDir = null; File javaHomeDir = null;
@ -287,7 +340,7 @@ public class LaunchSupport {
*/ */
private static int handleVmArgs(AppConfig appConfig) { private static int handleVmArgs(AppConfig appConfig) {
if (appConfig.getLaunchProperties() == null) { 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; return EXIT_FAILURE;
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 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(); public static String VMARGS_PLATFORM = "VMARGS_" + JavaFinder.getCurrentPlatform();
private Map<String, List<String>> propertyMap; private Map<String, List<String>> propertyMap;
private File launchPropertiesFile;
/** /**
* Creates a new launch properties object from the given launch properties file. * Creates a new launch properties object from the given launch properties file.
@ -57,9 +58,19 @@ public class LaunchProperties {
*/ */
public LaunchProperties(File launchPropertiesFile) public LaunchProperties(File launchPropertiesFile)
throws FileNotFoundException, IOException, ParseException { throws FileNotFoundException, IOException, ParseException {
this.launchPropertiesFile = launchPropertiesFile;
propertyMap = parseLaunchProperties(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. * Gets the Java home override directory to use for the launch.
* *

View file

@ -93,12 +93,14 @@ using any unzip program (built-in OS utilities, 7-Zip, WinZip, WinRAR, etc).
### Java Notes ### Java Notes
* Ghidra requires a [supported](#minimum-requirements) version of a Java Runtime and Development Kit * 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 on the PATH, or specified by the JAVA_HOME environment variable. If JAVA_HOME is specified
support, it will use that version of Java (if 1.8 or later) to assist in locating a supported it will take precedence over the PATH. If the version of Java found does not satisfy the
version on your system. If one cannot be automatically located, the user will be prompted to [minimum version](#minimum-requirements) required, it will use that version of Java
enter a path to the Java home directory to use (the Java home directory is the parent directory of (if 1.8 or later) to assist in locating a supported version on your system. If one cannot
Java's `bin` directory). This minimizes the impact Ghidra has on pre-existing configurations of be automatically located the user will be prompted to enter a path to the Java home directory
Java that other software may rely on. 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 * 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 [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 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 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 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 compatible version. Note that _some_ Java must still be on the PATH or specified by JAVA_HOME
the `JAVA_HOME_OVERRIDE` property. environment variable in order for Ghidra to use the `JAVA_HOME_OVERRIDE` property.
### Debugger Notes ### Debugger Notes
The Debugger now uses Python to connect to the host platform's native debuggers. This requires 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 `<GhidraInstallDir>` and When launching Ghidra with the provided scripts in `<GhidraInstallDir>` and
`<GhidraInstallDir>/support`, you may encounter the following error messages: `<GhidraInstallDir>/support`, you may encounter the following error messages:
* __Problem:__ _Java runtime not found._ * __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. Please see * __Solution:__ A Java runtime (java/java.exe) is required to be on the system PATH or the Java
the [requirements](#minimum-requirements) section for what version of Java must be pre-installed 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. for Ghidra to launch.
* __Problem:__ _Failed to find a supported JDK._ * __Problem:__ _Failed to find a supported JDK._
* __Solution:__ The Ghidra launch script uses the Java runtime on the system PATH to find a * __Solution:__ The Ghidra launch script uses the Java runtime on the system PATH or specified
supported version of a Java Development Kit (JDK) that Ghidra needs to complete its launch. by the JAVA_HOME environment variable to find a supported version of a Java Development Kit
Please see the [requirements](#minimum-requirements) section for what version of JDK must be (JDK) that Ghidra needs to complete its launch. Please see the
pre-installed for Ghidra to launch. [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._ * __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 * __Solution:__ Ghidra failed to launch in the background and the error message describing the