diff --git a/inc/Makefile-conf.mk b/inc/Makefile-conf.mk index 3141d00..3e1eb7d 100644 --- a/inc/Makefile-conf.mk +++ b/inc/Makefile-conf.mk @@ -21,11 +21,7 @@ include Makefile OBJECTDIR=build/${CONF}/${CND_PLATFORM} # Object Files -OBJECTFILES = ${OBJECTDIR}/argparser.o \ - ${OBJECTDIR}/utilsfuncs.o \ - ${OBJECTDIR}/ng.o \ - ${OBJECTDIR}/strlcpy.o \ - ${OBJECTDIR}/jrubyexe.o +OBJECTFILES = ${OBJECTDIR}/jrubyexe.o ifdef JAVA_HOME JAVA_INCLUDE = $(subst \,/,${JAVA_HOME})/include @@ -33,10 +29,16 @@ INCLUDES = "-I${JAVA_INCLUDE}" endif ifdef MINGW -OBJECTFILES += ${OBJECTDIR}/utilsfuncswin.o \ - ${OBJECTDIR}/platformlauncher.o \ - ${OBJECTDIR}/jvmlauncher.o \ - ${OBJECTDIR}/jruby.o +OBJECTFILES += +# Object Files +OBJECTFILES = ${OBJECTDIR}/argparser.o \ + ${OBJECTDIR}/utilsfuncs.o \ + ${OBJECTDIR}/ng.o \ + ${OBJECTDIR}/strlcpy.o \ + ${OBJECTDIR}/utilsfuncswin.o \ + ${OBJECTDIR}/platformlauncher.o \ + ${OBJECTDIR}/jvmlauncher.o \ + ${OBJECTDIR}/jruby.o INCLUDES += "-I${JAVA_INCLUDE}/win32" else OBJECTFILES += ${OBJECTDIR}/unixlauncher.o diff --git a/jrubyexe.cpp b/jrubyexe.cpp index da31c10..c53aa83 100644 --- a/jrubyexe.cpp +++ b/jrubyexe.cpp @@ -50,18 +50,18 @@ const char *CON_ATTACH_MSG = "*WARNING*: The non-console JRubyW launcher is forced to attach to console.\n" "This may cause unexpected behavior of CMD console. Use:\n" " start /wait jrubyw.exe -Xconsole attach [args]\n"; + +#include "utilsfuncs.h" #endif // JRUBYW #else #include "unixlauncher.h" #endif // WIN32 -#include "utilsfuncs.h" - int main(int argc, char *argv[], char* envp[]) { +#ifdef WIN32 checkLoggingArg(argc, argv, true); -#ifdef WIN32 #ifdef JRUBYW if (!isConsoleAttached()) { logMsg("Console is not attached, assume WINDOW mode"); @@ -78,7 +78,6 @@ int main(int argc, char *argv[], char* envp[]) { return loader.start("jruby.dll", argc - 1, argv + 1, argv[0]); #else // !WIN32 - UnixLauncher launcher; - return launcher.run(argc, argv, envp); + return unixlauncher_run(argc, argv, envp); #endif // WIN32 } diff --git a/unixlauncher.c b/unixlauncher.c new file mode 100644 index 0000000..2b38683 --- /dev/null +++ b/unixlauncher.c @@ -0,0 +1,143 @@ +#include +#include +#include +#include +#include +#include +#include + +/* + * Copyright 2009-2025 JRuby Team (www.jruby.org). + * + * This program finds JRUBY_HOME and executes the JRuby launcher script + * contained within it. + */ + +static const char script_name[] = "jruby.sh"; + + +static char *which(const char *const executable) { + const size_t exe_length = strlen(executable); + char *exe_path = NULL; + size_t exe_path_size = 0; + + // Iterate through PATH to find executable + char *dirs = getenv("PATH"); + if (dirs == NULL) { + return NULL; + } + size_t dirs_length = strlen(dirs); + // Temporarily replace null terminator with colon + dirs[dirs_length] = ':'; + + size_t dir_head = 0; + size_t i = 0; + do { + if (dirs[i] == ':') { + // Declare convenient path variables + char *const dir = dirs + dir_head; + const size_t dir_length = i - dir_head; + const size_t new_path_length = dir_length + exe_length + 1; + + // Allocate enough space for concatenated path + if (exe_path_size < new_path_length + 1) { + // Leave space for null terminator + exe_path = realloc(exe_path, new_path_length + 1); + exe_path_size = new_path_length + 1; + } + + // Concatenate path and executable + memcpy(exe_path, dir, dir_length); + exe_path[dir_length] = '/'; + memcpy(exe_path + dir_length + 1, executable, exe_length); + exe_path[new_path_length] = '\0'; + + // Check if we can execute + if (0 == access(exe_path, R_OK | X_OK)) { + goto success; + } + + dir_head = i + 1; + } + } while (dirs[i++]); + + // Lookup has failed, free if necessary and return NULL + if (exe_path != NULL) { + free(exe_path); + exe_path = NULL; + } +success: + // Restore null terminator + dirs[dirs_length] = '\0'; + + return exe_path; +} + + +int unixlauncher_run(int argc, char *argv[], char *envp[]) { + if (argc == 0 || argv[0][0] == '\0') { + fputs("Error: No executable provided!", stderr); + return 2; + } + + // Find ourselves + char *original_self = argv[0]; + char *self_path; + + // Detect whether argv[0] contains forward slashes + bool self_is_path = false; + for (size_t i = 0; original_self[i]; i++) { + if (original_self[i] == '/') { + self_is_path = true; + break; + } + } + + if (self_is_path) { // argv[0] is a path to an executable + self_path = realpath(original_self, NULL); + } else { // argv[0] is basename of executable + // Iterate through PATH to find script + self_path = which(argv[0]); + + if (self_path == NULL) { + fprintf(stderr, "Error: Could not find %s executable\n", script_name); + return 1; + } + + // Juggle malloc'd paths + char *real_path = realpath(self_path, NULL); + free(self_path); + self_path = real_path; + } + + // Find our parent directory + char *script_dir = dirname(self_path); + if (self_path != script_dir) { + // Free malloc'd self_path if dirname returned statically allocated string + free(self_path); + } + size_t script_dir_length = strlen(script_dir); + + // Allocate space for complete script path + size_t script_path_length = strlen(script_name) + script_dir_length + 1; + // Leave space for null terminator + char *script_path = malloc(script_path_length + 1); + + // Concatenate script dir and script name + memcpy(script_path, script_dir, script_dir_length); + script_path[script_dir_length] = '/'; + memcpy(script_path + script_dir_length + 1, script_name, strlen(script_name)); + script_path[script_path_length] = '\0'; + + // Reuse argv for script command line + argv[0] = script_path; + int ret = execv(argv[0], argv); + + if (ret < 0) { + fprintf(stderr, "%s: %s: %s\n", original_self, strerror(errno), script_path); + } + + free(self_path); + free(script_path); + return EXIT_FAILURE; +} diff --git a/unixlauncher.cpp b/unixlauncher.cpp deleted file mode 100644 index d030449..0000000 --- a/unixlauncher.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include -#include -#include -#include -#include -#include "unixlauncher.h" -#include "utilsfuncs.h" - -using namespace std; - -extern "C" int nailgunClientMain(int argc, char *argv[], char *env[]); - -UnixLauncher::UnixLauncher() - : ArgParser() -{ -} - -UnixLauncher::UnixLauncher(const UnixLauncher& orig) - : ArgParser(orig) -{ -} - -UnixLauncher::~UnixLauncher() { -} - -int UnixLauncher::run(int argc, char* argv[], char* envp[]) { - platformDir = argv[0]; - if (!initPlatformDir() || !parseArgs(argc - 1, argv + 1)) { - return 255; - } - - if (nailgunClient) { - progArgs.push_front("org.jruby.util.NailMain"); - char ** nailArgv = convertToArgvArray(progArgs); - int nailArgc = progArgs.size(); - - if (printCommandLine) { - printListToConsole(progArgs); - for (int i = 0; i < nailArgc; i++) { - free(nailArgv[i]); - } - delete[] nailArgv; - return 0; - } - return nailgunClientMain(progArgs.size(), (char**)nailArgv, envp); - } - - string java(""); - - if (getenv("JAVACMD") != NULL) { - java = getenv("JAVACMD"); - if (java.find_last_of('/') == -1) { - java = findOnPath(java.c_str()); - } - } else { - if (!jdkhome.empty()) { - java = jdkhome + "/bin/java"; - } else if (getenv("JAVA_HOME") != NULL) { - string java_home = string(getenv("JAVA_HOME")); - jdkhome = java_home; - java_home = trimTrailingBackslashes(java_home); - java = java_home + "/bin/java"; - } else { - java = findOnPath("java"); - } - } - - if (java.empty()) { - printToConsole("No `java' executable found on PATH."); - return 255; - } - - // still no jdk home, use other means to resolve it - if (jdkhome.empty()) { - char javaHomeCommand[] = "/usr/libexec/java_home"; - if (access(javaHomeCommand, R_OK | X_OK) != -1 && !checkDirectory(javaHomeCommand)) { - // try java_home command when not set (on MacOS) - FILE *fp; - char tmp[PATH_MAX + 1]; - - fp = popen(javaHomeCommand, "r"); - if (fp != NULL) { - fgets(tmp, sizeof(tmp), fp); - tmp[strcspn(tmp, "\n")] = 0; - jdkhome = tmp; - pclose(fp); - } else { - logErr(true, false, "failed to run %s", javaHomeCommand); - } - } else { - java = resolveSymlinks(java); - int home_index = java.find_last_of('/', java.find_last_of('/') - 1); - jdkhome = java.substr(0, home_index); - } - } - - prepareOptions(); - - list commandLine; - commandLine.push_back(java); - addOptionsToCommandLine(commandLine); - - logMsg("Command line:"); - for (list::iterator it = commandLine.begin(); it != commandLine.end(); ++it) { - logMsg("\t%s", it->c_str()); - } - - char** newArgv = convertToArgvArray(commandLine); - int newArgc = commandLine.size(); - - if (printCommandLine) { - printListToConsole(commandLine); - for (int i = 0; i < newArgc; i++) { - free(newArgv[i]); - } - delete[] newArgv; - return 0; - } - - if (!fileExists(java.c_str())) { - string msg = "No `java' exists at " + java + ", please double-check JAVA_HOME.\n"; - printToConsole(msg.c_str()); - return 255; - } - - execv(java.c_str(), newArgv); - - // shouldn't get here unless something bad happened with execv - logErr(true, true, "execv failed:"); - return 255; -} diff --git a/unixlauncher.h b/unixlauncher.h index 89a18e0..176c4f6 100644 --- a/unixlauncher.h +++ b/unixlauncher.h @@ -1,22 +1,20 @@ /* - * Copyright 2009-2010 JRuby Team (www.jruby.org). + * Copyright 2009-2025 JRuby Team (www.jruby.org). */ #ifndef _UNIXLAUNCHER_H_ #define _UNIXLAUNCHER_H_ -#include "argparser.h" +#ifdef __cplusplus +extern "C" +{ +#endif -class UnixLauncher : public ArgParser { -public: - UnixLauncher(); - virtual ~UnixLauncher(); +int unixlauncher_run(int argc, char *argv[], char *envp[]); - int run(int argc, char* argv[], char* envp[]); - -private: - UnixLauncher(const UnixLauncher& orig); -}; +#ifdef __cplusplus +} +#endif #endif // ! _UNIXLAUNCHER_H_